// ─── Tick Pipeline ─────────────────────────────────────────────────────────────
// Orchestrates the game tick as a read → compute → write pipeline.
// Eliminates cross-store getState() calls inside tick() by snapshotting all
// store state once, then batching all writes at the end.

import type { UIState } from './uiStore';
import type { PrestigeState } from './prestigeStore';
import type { ManaState } from './manaStore';
import type { CombatState } from './combat-state.types';
import type { CraftingState } from './craftingStore.types';
import type { AttunementStoreState } from './attunementStore';
import type { DisciplineStoreState } from './discipline-slice';
import type { GameCoordinatorState } from './gameStore.types';

// ─── Read-only snapshot of all store states at tick start ──────────────────────
export interface TickContext {
  game: GameCoordinatorState;
  ui: UIState;
  prestige: PrestigeState;
  mana: ManaState;
  combat: CombatState;
  crafting: CraftingState;
  attunement: AttunementStoreState;
  discipline: DisciplineStoreState;
}

// ─── Write batches — partial state to write back to each store ─────────────────
export interface TickWrites {
  game?: Partial<GameCoordinatorState>;
  ui?: Partial<UIState>;
  prestige?: Partial<PrestigeState>;
  mana?: Partial<ManaState>;
  combat?: Partial<CombatState>;
  crafting?: Partial<CraftingState>;
  attunement?: Partial<AttunementStoreState>;
  discipline?: Partial<DisciplineStoreState>;
  logs: string[];
}

// ─── Rehydration guard ─────────────────────────────────────────────────────────
// Zustand persist sets `_persist.rehydrated` after hydration completes.
// We check a proxy flag on each store's state object instead, since Zustand
// doesn't expose a public rehydration flag.

/** Check if a persist store has rehydrated by looking for non-default state. */
export function hasRehydrated(state: Record<string, unknown>, keys: string[]): boolean {
  // If any persisted key has a non-default value, the store has rehydrated.
  // For our purposes, we just check that the state object is not empty.
  return keys.some((k) => state[k] !== undefined);
}

// ─── Pipeline orchestrator ─────────────────────────────────────────────────────

/**
 * Build a TickContext by snapshotting all store states.
 * Call this ONCE at the start of tick().
 */
export function buildTickContext(params: {
  game: GameCoordinatorState;
  ui: UIState;
  prestige: PrestigeState;
  mana: ManaState;
  combat: CombatState;
  crafting: CraftingState;
  attunement: AttunementStoreState;
  discipline: DisciplineStoreState;
}): TickContext {
  return { ...params };
}

/**
 * Apply all writes to their respective stores.
 * Call this ONCE at the end of tick().
 */
export function applyTickWrites(
  writes: TickWrites,
  setters: {
    setGame: (w: Partial<GameCoordinatorState>) => void;
    setUI: (w: Partial<UIState>) => void;
    setPrestige: (w: Partial<PrestigeState>) => void;
    setMana: (w: Partial<ManaState>) => void;
    setCombat: (w: Partial<CombatState>) => void;
    setCrafting: (w: Partial<CraftingState>) => void;
    setAttunement: (w: Partial<AttunementStoreState>) => void;
    setDiscipline: (w: Partial<DisciplineStoreState>) => void;
    addLogs: (msgs: string[]) => void;
  },
): void {
  const {
    setGame, setUI, setPrestige, setMana,
    setCombat, setCrafting, setAttunement, setDiscipline, addLogs,
  } = setters;
  if (writes.game) setGame(writes.game);
  if (writes.ui) setUI(writes.ui);
  if (writes.prestige) setPrestige(writes.prestige);
  if (writes.mana) setMana(writes.mana);
  if (writes.combat) setCombat(writes.combat);
  if (writes.crafting) setCrafting(writes.crafting);
  if (writes.attunement) setAttunement(writes.attunement);
  if (writes.discipline) setDiscipline(writes.discipline);
  if (writes.logs.length > 0) addLogs(writes.logs);
}
