package backup

import "time"

// Restore op-status (Part B): a lightweight, in-memory surface for the ASYNC restore family so the
// backups page can show a progress banner (running → success/failure) instead of blocking the HTTP
// request until the restore completes. It is display-only and mutex-guarded on the Manager's `mu`;
// it does NOT gate concurrency (that stays the restore functions' internal single-flight acquire).
// In-memory only — lost on a controller restart (same precedent as notification cooldowns); a page
// load mid-op after a restart simply shows no banner.

// RestoreOpResult is the terminal record of the most recent restore op.
type RestoreOpResult struct {
	Op         string    `json:"op"`      // "restore" | "tier2-restore" | "offbox-restore"
	Stack      string    `json:"stack"`
	OK         bool      `json:"ok"`
	Message    string    `json:"message"`
	FinishedAt time.Time `json:"finished_at"`
}

// RestoreOpStatus is the shape served at GET /api/backup/restore-status.
type RestoreOpStatus struct {
	Running   bool             `json:"running"`
	Op        string           `json:"op,omitempty"`
	Stack     string           `json:"stack,omitempty"`
	StartedAt time.Time        `json:"started_at,omitempty"`
	Last      *RestoreOpResult `json:"last,omitempty"`
}

// BeginRestoreOp marks a restore op in flight (called by the handler just before launching the
// background goroutine). Idempotent enough for display; concurrency is enforced elsewhere.
func (m *Manager) BeginRestoreOp(op, stack string) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.opRunning = true
	m.opName = op
	m.opStack = stack
	m.opStartedAt = time.Now()
}

// EndRestoreOp records the terminal result (called from the goroutine on completion, success or
// failure). Message carries the error (failure) or a human note like the scratch path (offbox).
func (m *Manager) EndRestoreOp(ok bool, message string) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.opLast = &RestoreOpResult{
		Op:         m.opName,
		Stack:      m.opStack,
		OK:         ok,
		Message:    message,
		FinishedAt: time.Now(),
	}
	m.opRunning = false
}

// RestoreStatus returns a deep copy of the current restore op-status for the page/API.
func (m *Manager) RestoreStatus() RestoreOpStatus {
	m.mu.Lock()
	defer m.mu.Unlock()
	st := RestoreOpStatus{
		Running:   m.opRunning,
		Op:        m.opName,
		Stack:     m.opStack,
		StartedAt: m.opStartedAt,
	}
	if m.opLast != nil {
		cp := *m.opLast
		st.Last = &cp
	}
	return st
}
