/**
 * useThemeGame — the Corrosion design-system theming contract.
 *
 * Drives `data-theme` and `data-game` on <html>, the two attributes the token
 * system keys off (see styles/tokens/colors.css + game-themes.css):
 *   <html data-theme="dark|light" data-game="rust|dune|conan|soulmask|...">
 *
 * Dark is primary; Rust (Oxide Orange) is the default/brand accent.
 *
 * Runtime swaps add the `cc-skin-swap` class for one frame so every
 * accent-consuming surface repaints immediately — without it Chrome leaves
 * elements that read var(--accent) AND have a color/bg transition on the old
 * accent until the next reflow (see styles/tokens/base.css + readme).
 */
import { ref, readonly } from 'vue'

export type Theme = 'dark' | 'light'
export type Game =
  | 'rust'
  | 'dune'
  | 'conan'
  | 'soulmask'
  | 'ark'
  | 'valheim'
  | 'palworld'

/** The fleet filter: 'all' (every game) plus each individual game. */
export type ActiveGame = 'all' | Game

const THEME_KEY = 'cc-theme'
const GAME_KEY = 'cc-game'
const ACTIVE_GAME_KEY = 'cc-active-game'

const VALID_THEMES: readonly Theme[] = ['dark', 'light']
const VALID_GAMES: readonly Game[] = [
  'rust',
  'dune',
  'conan',
  'soulmask',
  'ark',
  'valheim',
  'palworld',
]

// Module-scope singletons so every caller shares one reactive source.
const theme = ref<Theme>('dark')
const game = ref<Game>('rust')
// Fleet filter: 'all' shows every game and uses the neutral house skin (Oxide);
// a specific game both filters the fleet AND re-skins the shell (the drill-in rule).
const activeGame = ref<ActiveGame>('all')

function apply(): void {
  const el = document.documentElement
  el.classList.add('cc-skin-swap')
  el.setAttribute('data-theme', theme.value)
  el.setAttribute('data-game', game.value)
  // Keep Tailwind's `dark` class in sync — existing views may use `dark:` utilities.
  el.classList.toggle('dark', theme.value === 'dark')
  // Drop the swap guard after the paint that picked up the new accent.
  requestAnimationFrame(() =>
    requestAnimationFrame(() => el.classList.remove('cc-skin-swap')),
  )
}

let initialized = false

/**
 * Read persisted prefs and apply them to <html>. Call once at app start
 * (after a tiny inline FOUC guard in index.html has set the initial attrs).
 */
export function initThemeGame(): void {
  if (initialized) return
  const t = localStorage.getItem(THEME_KEY)
  if (t && (VALID_THEMES as string[]).includes(t)) theme.value = t as Theme
  const ag = localStorage.getItem(ACTIVE_GAME_KEY)
  if (ag && (ag === 'all' || (VALID_GAMES as string[]).includes(ag))) {
    activeGame.value = ag as ActiveGame
  }
  // Skin follows the filter: 'all' -> neutral house (rust/oxide), else the game.
  game.value = activeGame.value === 'all' ? 'rust' : activeGame.value
  apply()
  initialized = true
}

/** Set the active game + its matching skin and paint <html>. Shared by the
 *  manual switcher (persist=true → becomes an operator override) and the
 *  fleet-derived sync (persist=false → stays "auto", re-tracks the fleet). */
function applyActiveGame(g: ActiveGame, persist: boolean): void {
  activeGame.value = g
  game.value = g === 'all' ? 'rust' : g
  if (persist) {
    localStorage.setItem(ACTIVE_GAME_KEY, g)
    localStorage.setItem(GAME_KEY, game.value)
  }
  apply()
}

/**
 * Derive the active game from the deployed fleet — the game instances are the
 * source of truth for which game(s) a license runs (game_instances.game, set by
 * re-Agent). Exactly one game deployed → skin the shell to it; zero or
 * multiple → 'all' (neutral house skin).
 *
 * NO-OP when the operator has a manual pick stored (cc-active-game present): an
 * explicit GameSwitcher choice always beats the heuristic. Does not persist, so
 * an un-overridden panel keeps tracking the fleet across sessions and as
 * instances are added/removed. Safe to call repeatedly (idempotent).
 */
export function syncActiveGameFromFleet(games: readonly string[]): void {
  if (localStorage.getItem(ACTIVE_GAME_KEY)) return // operator override wins
  const distinct = Array.from(
    new Set(games.filter((g): g is Game => (VALID_GAMES as string[]).includes(g))),
  )
  const derived: ActiveGame = distinct.length === 1 ? distinct[0]! : 'all'
  if (derived === activeGame.value) return
  applyActiveGame(derived, false)
}

export function useThemeGame() {
  function setTheme(t: Theme): void {
    theme.value = t
    localStorage.setItem(THEME_KEY, t)
    apply()
  }
  function setGame(g: Game): void {
    game.value = g
    localStorage.setItem(GAME_KEY, g)
    apply()
  }
  function setActiveGame(g: ActiveGame): void {
    // Manual pick: persist so it overrides fleet auto-derive from now on.
    // 'all' uses the neutral house skin (rust/oxide); a game re-skins to itself.
    applyActiveGame(g, true)
  }
  function toggleTheme(): void {
    setTheme(theme.value === 'dark' ? 'light' : 'dark')
  }
  return {
    theme: readonly(theme),
    game: readonly(game),
    activeGame: readonly(activeGame),
    setTheme,
    setGame,
    setActiveGame,
    toggleTheme,
  }
}
