package selfupdate

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
)

const stateFileName = "update-state.json"

// UpdateState tracks the last update attempt. Persisted to disk as audit log.
type UpdateState struct {
	Status          string `json:"status"`                   // "pending", "success", "failed"
	PreviousVersion string `json:"previous_version"`
	PreviousImage   string `json:"previous_image"`
	TargetVersion   string `json:"target_version"`
	TargetImage     string `json:"target_image"`
	InitiatedAt     string `json:"initiated_at"`             // RFC3339
	InitiatedBy     string `json:"initiated_by"`             // "manual" or "auto"
	CompletedAt     string `json:"completed_at,omitempty"`
	Error           string `json:"error,omitempty"`
}

// LoadState reads the update state file. Returns nil, nil if file doesn't exist.
func LoadState(dataDir string) (*UpdateState, error) {
	path := filepath.Join(dataDir, stateFileName)
	data, err := os.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, fmt.Errorf("reading state file: %w", err)
	}

	var state UpdateState
	if err := json.Unmarshal(data, &state); err != nil {
		return nil, fmt.Errorf("parsing state file: %w", err)
	}
	return &state, nil
}

// SaveState writes the state file atomically (write to .tmp, then rename).
func SaveState(dataDir string, state *UpdateState) error {
	path := filepath.Join(dataDir, stateFileName)
	tmpPath := path + ".tmp"

	data, err := json.MarshalIndent(state, "", "  ")
	if err != nil {
		return fmt.Errorf("marshaling state: %w", err)
	}

	if err := os.WriteFile(tmpPath, data, 0644); err != nil {
		return fmt.Errorf("writing temp state file: %w", err)
	}

	if err := os.Rename(tmpPath, path); err != nil {
		return fmt.Errorf("renaming state file: %w", err)
	}

	return nil
}

// ClearState removes the state file. Used for cleanup.
func ClearState(dataDir string, logger *log.Logger) {
	path := filepath.Join(dataDir, stateFileName)
	if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
		logger.Printf("[WARN] [selfupdate] Failed to clear update state file: %v", err)
		return
	}
	logger.Printf("[INFO] [selfupdate] Update state cleared")
}
