package app

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

// prefs is the TUI's local, persisted preferences (display-only client state — kept out
// of the server config, which is shared/replayed). Stored as JSON in the correx config dir.
type prefs struct {
	StatusbarHidden     []string `json:"statusbarHidden"`
	InlineActionsHidden bool     `json:"inlineActionsHidden"`
	ThinkingShown       bool     `json:"thinkingShown"`
}

// statusSegment is one toggleable status-bar segment. The always-on segments (correx label,
// connection, session name, spinner, background-updates) are not listed — they are load-bearing.
type statusSegment struct{ id, label string }

var statusSegments = []statusSegment{
	{"stage", "current stage (⟐)"},
	{"status", "session status"},
	{"workspace", "workspace path (⌂)"},
	{"model", "model name"},
	{"clock", "last-event clock"},
	{"gauge", "resource gauge"},
}

func prefsPath() string {
	dir := os.Getenv("CORREX_CONFIG_HOME")
	if dir == "" {
		home, err := os.UserHomeDir()
		if err != nil {
			return ""
		}
		dir = filepath.Join(home, ".config", "correx")
	}
	return filepath.Join(dir, "tui-prefs.json")
}

// loadPrefs reads the whole prefs file (best-effort: a missing or corrupt file yields the
// zero value, i.e. everything shown / actions visible).
func loadPrefs() prefs {
	var p prefs
	path := prefsPath()
	if path == "" {
		return p
	}
	if data, err := os.ReadFile(path); err == nil {
		_ = json.Unmarshal(data, &p)
	}
	return p
}

// savePrefs writes the whole prefs file (best-effort; ignores IO errors so a read-only home
// never crashes the UI). Callers load, mutate one field, then save so nothing is clobbered.
func savePrefs(p prefs) {
	path := prefsPath()
	if path == "" {
		return
	}
	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
		return
	}
	if data, err := json.MarshalIndent(p, "", "  "); err == nil {
		_ = os.WriteFile(path, data, 0o644)
	}
}

// loadStatusbarHidden reads the persisted hidden-segment set (best-effort: a missing or
// corrupt file yields an empty set, i.e. everything shown).
func loadStatusbarHidden() map[string]bool {
	out := map[string]bool{}
	for _, id := range loadPrefs().StatusbarHidden {
		out[id] = true
	}
	return out
}

// saveStatusbarHidden writes the hidden set back to disk, preserving the other prefs fields.
// Order follows statusSegments for a stable file.
func saveStatusbarHidden(hidden map[string]bool) {
	var ids []string
	for _, seg := range statusSegments {
		if hidden[seg.id] {
			ids = append(ids, seg.id)
		}
	}
	p := loadPrefs()
	p.StatusbarHidden = ids
	savePrefs(p)
}

// saveInlineActionsHidden persists the inline-action-rows toggle, preserving other prefs fields.
func saveInlineActionsHidden(hidden bool) {
	p := loadPrefs()
	p.InlineActionsHidden = hidden
	savePrefs(p)
}

// saveThinkingShown persists the reasoning-blocks toggle, preserving other prefs fields.
func saveThinkingShown(shown bool) {
	p := loadPrefs()
	p.ThinkingShown = shown
	savePrefs(p)
}
