// ─── Prestige Store ───────────────────────────────────────────────────────────
// Handles insight, prestige upgrades, loops, pacts

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { createSafeStorage } from '../utils/safe-persist';
import { PRESTIGE_DEF } from '../constants';
import { getGuardianForFloor } from '../data/guardian-encounters';
import { useManaStore } from './manaStore';
import { okVoid, fail, ErrorCode } from '../utils/result';
import type { Result } from '../utils/result';

// ─── Prestige State (data only) ──────────────────────────────────────────────

export interface PrestigeState {
  // Loop counter
  loopCount: number;

  // Insight
  insight: number;
  totalInsight: number;
  loopInsight: number;

  // Prestige upgrades
  prestigeUpgrades: Record<string, number>;
  pactSlots: number;

  // Guardian pacts
  defeatedGuardians: number[];
  signedPacts: number[];
  signedPactDetails: Record<number, {
    floor: number;
    guardianId: string;
    signedAt: { day: number; hour: number };
    skillLevels: Record<string, number>;
  }>;
  pactRitualFloor: number | null;
  pactRitualProgress: number;
}

// ─── Prestige Actions ────────────────────────────────────────────────────────

export interface PrestigeActions {
  doPrestige: (id: string) => Result<void>;
  startPactRitual: (floor: number, rawMana: number) => Result<void>;
  cancelPactRitual: () => void;
  completePactRitual: (addLog: (msg: string) => void) => void;
  updatePactRitualProgress: (hours: number) => void;
  removePact: (floor: number) => void;
  defeatGuardian: (floor: number) => void;

  // Methods called by gameStore
  addSignedPact: (floor: number) => void;
  removeDefeatedGuardian: (floor: number) => void;
  setPactRitualFloor: (floor: number | null) => void;
  addDefeatedGuardian: (floor: number) => void;
  incrementLoopCount: () => void;
  resetPrestigeForNewLoop: (
    totalInsight: number,
    prestigeUpgrades: Record<string, number>,
  ) => void;

  // Loop management
  startNewLoop: (insightGained: number) => void;
  setLoopInsight: (insight: number) => void;

  // Reset
  resetPrestige: () => void;

  // Debug helpers
  debugSetSignedPacts: (pacts: number[]) => void;
  debugSetPactDetails: (details: Record<number, {
    floor: number;
    guardianId: string;
    signedAt: { day: number; hour: number };
    skillLevels: Record<string, number>;
  }>) => void;
}

// ─── Combined Prestige Store Type ────────────────────────────────────────────

export type PrestigeStore = PrestigeState & PrestigeActions;

// ─── Initial State ───────────────────────────────────────────────────────────

const initialState: PrestigeState = {
  loopCount: 0,
  insight: 0,
  totalInsight: 0,
  loopInsight: 0,
  prestigeUpgrades: {},
  pactSlots: 1,
  defeatedGuardians: [],
  signedPacts: [],
  signedPactDetails: {},
  pactRitualFloor: null,
  pactRitualProgress: 0,
};

export const usePrestigeStore = create<PrestigeStore>()(
  persist(
    (set, get) => ({
      ...initialState,

      doPrestige: (id: string) => {
        const state = get();
        const pd = PRESTIGE_DEF[id];
        if (!pd) return fail(ErrorCode.INVALID_PRESTIGE_ID, `Unknown prestige upgrade: ${id}`);

        const lvl = state.prestigeUpgrades[id] || 0;
        if (lvl >= pd.max) return fail(ErrorCode.PRESTIGE_MAX_LEVEL, `Upgrade ${id} is already at max level (${pd.max})`);
        if (state.insight < pd.cost) return fail(ErrorCode.INSUFFICIENT_INSIGHT, `Need ${pd.cost} insight, have ${state.insight}`);

        const newPU = { ...state.prestigeUpgrades, [id]: lvl + 1 };
        set({
          insight: state.insight - pd.cost,
          prestigeUpgrades: newPU,
          pactSlots: id === 'pactBinding' ? state.pactSlots + 1 : state.pactSlots,
        });
        return okVoid();
      },

      startPactRitual: (floor: number, rawMana: number) => {
        const state = get();
        const guardian = getGuardianForFloor(floor);
        if (!guardian) return fail(ErrorCode.INVALID_INPUT, `No guardian at floor ${floor}`);

        if (!state.defeatedGuardians.includes(floor)) return fail(ErrorCode.GUARDIAN_NOT_DEFEATED, `Guardian at floor ${floor} has not been defeated`);
        if (state.signedPacts.includes(floor)) return fail(ErrorCode.PACT_ALREADY_SIGNED, `Pact with ${guardian.name} is already signed`);
        if (state.signedPacts.length >= state.pactSlots) return fail(ErrorCode.PACT_SLOTS_FULL, `All pact slots are full (${state.pactSlots})`);
        if (rawMana < guardian.pactCost) return fail(ErrorCode.INSUFFICIENT_MANA, `Need ${guardian.pactCost} raw mana, have ${rawMana}`);
        if (state.pactRitualFloor !== null) return fail(ErrorCode.RITUAL_IN_PROGRESS, `A pact ritual is already in progress for floor ${state.pactRitualFloor}`);

        // Deduct raw mana cost upfront (spec §2.2 step 7)
        const manaStore = useManaStore.getState();
        const deducted = manaStore.spendRawMana(guardian.pactCost);
        if (!deducted) return fail(ErrorCode.INSUFFICIENT_MANA, `Need ${guardian.pactCost} raw mana, have ${manaStore.rawMana}`);

        set({
          pactRitualFloor: floor,
          pactRitualProgress: 0,
        });
        return okVoid();
      },

      cancelPactRitual: () => {
        const state = get();
        if (state.pactRitualFloor !== null) {
          const guardian = getGuardianForFloor(state.pactRitualFloor);
          if (guardian) {
            useManaStore.setState((s) => ({
              rawMana: s.rawMana + guardian.pactCost,
            }));
          }
        }
        set({
          pactRitualFloor: null,
          pactRitualProgress: 0,
        });
      },

      completePactRitual: (addLog: (msg: string) => void) => {
        const state = get();
        if (state.pactRitualFloor === null) return;

        const guardian = getGuardianForFloor(state.pactRitualFloor);
        if (!guardian) return;

        // Unlock mana types granted by this guardian
        const manaStore = useManaStore.getState();
        for (const manaType of guardian.unlocksMana || []) {
          const result = manaStore.unlockElement(manaType, 0);
          if (result.success) {
            addLog(`✨ ${manaType.charAt(0).toUpperCase() + manaType.slice(1)} mana unlocked!`);
          }
        }

        const floor = state.pactRitualFloor;
        set({
          signedPacts: [...state.signedPacts, floor],
          defeatedGuardians: state.defeatedGuardians.filter(f => f !== floor),
          signedPactDetails: {
            ...state.signedPactDetails,
            [floor]: {
              floor,
              guardianId: guardian.name || `floor-${floor}`,
              signedAt: { day: 0, hour: 0 },
              skillLevels: {},
            },
          },
          pactRitualFloor: null,
          pactRitualProgress: 0,
        });

        addLog(`📜 Pact signed with ${guardian.name}! You have gained their boons.`);
      },

      updatePactRitualProgress: (hours: number) => {
        set((state) => ({
          pactRitualProgress: state.pactRitualProgress + hours,
        }));
      },

      removePact: (floor: number) => {
        set((state) => ({
          signedPacts: state.signedPacts.filter(f => f !== floor),
        }));
      },

      defeatGuardian: (floor: number) => {
        const state = get();
        if (state.defeatedGuardians.includes(floor) || state.signedPacts.includes(floor)) return;

        set({
          defeatedGuardians: [...state.defeatedGuardians, floor],
        });
      },

      addSignedPact: (floor: number) => {
        const state = get();
        if (state.signedPacts.includes(floor)) return;
        set({ signedPacts: [...state.signedPacts, floor] });
      },

      removeDefeatedGuardian: (floor: number) => {
        set((state) => ({
          defeatedGuardians: state.defeatedGuardians.filter(f => f !== floor),
        }));
      },

      setPactRitualFloor: (floor: number | null) => {
        set({ pactRitualFloor: floor, pactRitualProgress: 0 });
      },

      addDefeatedGuardian: (floor: number) => {
        const state = get();
        if (state.defeatedGuardians.includes(floor) || state.signedPacts.includes(floor)) return;
        set({ defeatedGuardians: [...state.defeatedGuardians, floor] });
      },

      incrementLoopCount: () => {
        set((state) => ({ loopCount: state.loopCount + 1 }));
      },

      resetPrestigeForNewLoop: (
        totalInsight: number,
        prestigeUpgrades: Record<string, number>,
      ) => {
        set({
          insight: totalInsight,
          prestigeUpgrades,
          // Reset loop-specific state
          defeatedGuardians: [],
          signedPacts: [],
          pactRitualFloor: null,
          pactRitualProgress: 0,
          loopInsight: 0,
          // NOTE: signedPactDetails is intentionally NOT reset here.
          // Per spec §5.1, it persists across loops for historical tracking.
        });
      },

      startNewLoop: (insightGained: number) => {
        const state = get();
        set({
          loopCount: state.loopCount + 1,
          insight: state.insight + insightGained,
          totalInsight: state.totalInsight + insightGained,
          loopInsight: 0,
          // Reset loop-specific state
          defeatedGuardians: [],
          signedPacts: [],
          pactRitualFloor: null,
          pactRitualProgress: 0,
        });
      },

      setLoopInsight: (insight: number) => {
        set({ loopInsight: insight });
      },

      resetPrestige: () => {
        set(initialState);
      },

      // Debug helpers
      debugSetSignedPacts: (pacts: number[]) => {
        set({ signedPacts: pacts });
      },
      debugSetPactDetails: (details: Record<number, {
        floor: number;
        guardianId: string;
        signedAt: { day: number; hour: number };
        skillLevels: Record<string, number>;
      }>) => {
        set({ signedPactDetails: details });
      },
    }),
    {
      storage: createSafeStorage(),
      name: 'mana-loop-prestige',
      version: 1,
      partialize: (state) => ({
        loopCount: state.loopCount,
        insight: state.insight,
        totalInsight: state.totalInsight,
        loopInsight: state.loopInsight,
        prestigeUpgrades: state.prestigeUpgrades,
        pactSlots: state.pactSlots,
        defeatedGuardians: state.defeatedGuardians,
        signedPacts: state.signedPacts,
        signedPactDetails: state.signedPactDetails,
        pactRitualFloor: state.pactRitualFloor,
        pactRitualProgress: state.pactRitualProgress,
      }),
    }
  )
);
