// ─── Game Store (Coordinator) ─────────────────────────────────────────────────
// Manages: day, hour, incursionStrength, containmentWards
// Coordinate tick function across all stores

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { TICK_MS, HOURS_PER_TICK, MAX_DAY, SPELLS_DEF, GUARDIANS, getStudySpeedMultiplier } from '../constants';
import { hasSpecial, SPECIAL_EFFECTS } from '../effects/special-effects';
import { computeEquipmentEffects } from '../effects';
import type { ComputedEffects } from '../effects/upgrade-effects.types';

import { computeDisciplineEffects } from '../effects/discipline-effects';
import {
  computeMaxMana,
  computeRegen,
  getFloorElement,
  getFloorMaxHP,
  getMeditationBonus,
  getIncursionStrength,
  calcInsight,
  calcDamage,
  deductSpellCost,
  canAffordSpellCost,
} from '../utils';
import { useUIStore } from './uiStore';
import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { useCombatStore, makeInitialSpells } from './combatStore';
import { useAttunementStore } from './attunementStore';
import { useCraftingStore } from './craftingStore';
import { useDisciplineStore } from './discipline-slice';
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '../data/attunements';
import { createResetGame, createGatherMana } from './gameActions';
import { createStartNewLoop } from './gameLoopActions';

export interface GameCoordinatorState {
  day: number;
  hour: number;
  incursionStrength: number;
  containmentWards: number;
  initialized: boolean;
}

export interface GameCoordinatorStore extends GameCoordinatorState {
  tick: () => void;
  resetGame: () => void;
  togglePause: () => void;
  startNewLoop: () => void;
  initGame: () => void;
  gatherMana: () => void;
}

const initialState: GameCoordinatorState = {
  day: 1,
  hour: 0,
  incursionStrength: 0,
  containmentWards: 0,
  initialized: false,
};

export const useGameStore = create<GameCoordinatorStore>()(
  persist(
    (set, get) => ({
      ...initialState,

      initGame: () => {
        set({ initialized: true });
      },

      tick: () => {
        const uiState = useUIStore.getState();
        if (uiState.gameOver || uiState.paused) return;

        // Helper for logging
        const addLog = (msg: string) => useUIStore.getState().addLog(msg);

        // Get all store states
        const prestigeState = usePrestigeStore.getState();
        const manaState = useManaStore.getState();
        const combatState = useCombatStore.getState();
        const craftingState = useCraftingStore.getState();
        const disciplineStoreState = useDisciplineStore.getState();

        // Compute equipment specials from enchanted gear
        const equipmentEffects = computeEquipmentEffects(
          craftingState.equipmentInstances || {},
          craftingState.equippedInstances || {}
        );
        // Compute discipline specials from active discipline perks
        const disciplineEffects = computeDisciplineEffects(disciplineStoreState as any);
        // Merge all specials into a single set for hasSpecial checks
        const allSpecials = new Set<string>([
          ...equipmentEffects.specials,
          ...disciplineEffects.specials,
        ]);
        const effects = { specials: allSpecials } as ComputedEffects;

        const maxMana = computeMaxMana(
          { skills: {}, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
          undefined,
          disciplineEffects,
        );
        const baseRegen = computeRegen(
          { skills: {}, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunements: {} },
          undefined,
          disciplineEffects,
        );

        // Time progression
        let hour = get().hour + HOURS_PER_TICK;
        let day = get().day;
        if (hour >= 24) {
          hour -= 24;
          day += 1;
        }

        // Check for loop end
        if (day > MAX_DAY) {
          const insightGained = calcInsight({
            maxFloorReached: combatState.maxFloorReached,
            totalManaGathered: manaState.totalManaGathered,
            signedPacts: prestigeState.signedPacts,
            prestigeUpgrades: prestigeState.prestigeUpgrades,
            skills: {},
          }, disciplineEffects);

          addLog(`⏰ The loop ends. Gained ${insightGained} Insight.`);
          useUIStore.getState().setGameOver(true, false);
          usePrestigeStore.getState().setLoopInsight(insightGained);
          set({ day, hour });
          return;
        }

        // Check for victory
        if (combatState.maxFloorReached >= 100 && prestigeState.signedPacts.includes(100)) {
          const insightGained = calcInsight({
            maxFloorReached: combatState.maxFloorReached,
            totalManaGathered: manaState.totalManaGathered,
            signedPacts: prestigeState.signedPacts,
            prestigeUpgrades: prestigeState.prestigeUpgrades,
            skills: {},
          }, disciplineEffects) * 3;

          addLog(`🏆 VICTORY! The Awakened One falls! Gained ${insightGained} Insight!`);
          useUIStore.getState().setGameOver(true, true);
          usePrestigeStore.getState().setLoopInsight(insightGained);
          return;
        }

        // Incursion
        const incursionStrength = getIncursionStrength(day, hour);

        // Meditation bonus tracking and regen calculation
        let meditateTicks = manaState.meditateTicks;
        let meditationMultiplier = 1;

        if (combatState.currentAction === 'meditate') {
          meditateTicks++;
          meditationMultiplier = getMeditationBonus(meditateTicks, {}, 1);
        } else {
          meditateTicks = 0;
        }

        // Calculate total attunement conversion per tick (to subtract from regen)
        const attunementState = useAttunementStore.getState();
        let totalConversionPerTick = 0;
        Object.entries(attunementState.attunements).forEach(([id, state]) => {
          if (!state.active) return;
          const def = ATTUNEMENTS_DEF[id];
          if (!def || def.conversionRate <= 0 || !def.primaryManaType) return;

          const scaledRate = getAttunementConversionRate(id, state.level || 1);
          totalConversionPerTick += scaledRate * HOURS_PER_TICK;
        });

        // Calculate effective regen with incursion, meditation, and attunement conversion
        const effectiveRegen = Math.max(0, baseRegen * (1 - incursionStrength) * meditationMultiplier - totalConversionPerTick);

        // Mana regeneration (now includes attunement conversion deduction)
        let rawMana = Math.min(manaState.rawMana + effectiveRegen * HOURS_PER_TICK, maxMana);
        let elements = { ...manaState.elements };

        // Apply attunement conversion (add to primary mana types)
        Object.entries(attunementState.attunements).forEach(([id, state]) => {
          if (!state.active) return;
          const def = ATTUNEMENTS_DEF[id];
          if (!def || def.conversionRate <= 0 || !def.primaryManaType) return;

          const scaledRate = getAttunementConversionRate(id, state.level || 1);
          const conversionThisTick = scaledRate * HOURS_PER_TICK;

          // Add to primary mana type (cost already deducted from regen)
          if (elements[def.primaryManaType]) {
            elements[def.primaryManaType].current = Math.min(
              elements[def.primaryManaType].max,
              elements[def.primaryManaType].current + conversionThisTick
            );
          }
        });
        let totalManaGathered = manaState.totalManaGathered;

        // Convert action - delegate to manaStore
        if (combatState.currentAction === 'convert') {
          const convertResult = useManaStore.getState().processConvertAction(rawMana);
          if (convertResult) {
            rawMana = convertResult.rawMana;
            elements = convertResult.elements;
          }
        }

        // Pact ritual progress
        if (prestigeState.pactRitualFloor !== null) {
          const guardian = GUARDIANS[prestigeState.pactRitualFloor];
          if (guardian) {
            const pactAffinityBonus = 1 - (prestigeState.prestigeUpgrades.pactAffinity || 0) * 0.1;
            const requiredTime = guardian.pactTime * pactAffinityBonus;
            const newProgress = prestigeState.pactRitualProgress + HOURS_PER_TICK;

            if (newProgress >= requiredTime) {
              addLog(`📜 Pact signed with ${guardian.name}! You have gained their boons.`);
              usePrestigeStore.getState().addSignedPact(prestigeState.pactRitualFloor);
              usePrestigeStore.getState().removeDefeatedGuardian(prestigeState.pactRitualFloor);
              usePrestigeStore.getState().setPactRitualFloor(null);
            } else {
              usePrestigeStore.getState().updatePactRitualProgress(newProgress);
            }
          }
        }

        // Combat - delegate to combatStore
        if (combatState.currentAction === 'climb') {
          const combatResult = useCombatStore.getState().processCombatTick(
            rawMana,
            elements,
            maxMana,
            1,
            (floor, wasGuardian) => {
              if (wasGuardian) {
                addLog(`⚔️ ${GUARDIANS[floor]?.name || 'Guardian'} defeated! Visit the Grimoire to sign a pact.`);
              } else if (floor % 5 === 0) {
                addLog(`🏰 Floor ${floor} cleared!`);
              }
            },
            (damage) => {
              // Apply upgrade damage multipliers and bonuses
              let dmg = damage;

              // Executioner: +100% damage to enemies below 25% HP
              if (hasSpecial(effects, SPECIAL_EFFECTS.EXECUTIONER) && combatState.floorHP / combatState.floorMaxHP < 0.25) {
                dmg *= 2;
              }

              // Berserker: +50% damage when below 50% mana
              if (hasSpecial(effects, SPECIAL_EFFECTS.BERSERKER) && rawMana < maxMana * 0.5) {
                dmg *= 1.5;
              }

              return { rawMana, elements, modifiedDamage: dmg };
            }
          );

          rawMana = combatResult.rawMana;
          elements = combatResult.elements;
          totalManaGathered += combatResult.totalManaGathered || 0;

          // Log any messages from combat
          if (combatResult.logMessages) {
            combatResult.logMessages.forEach(msg => addLog(msg));
          }
        }

        // Update all stores with new state
        useManaStore.setState({
          rawMana,
          meditateTicks,
          totalManaGathered,
          elements,
        });

        set({
          day,
          hour,
          incursionStrength,
        });
      },

      resetGame: createResetGame(set, initialState),
      togglePause: () => {
        useUIStore.getState().togglePause();
      },
      startNewLoop: createStartNewLoop(set),
      gatherMana: createGatherMana(),
    }),
    {
      name: 'mana-loop-game-storage',
      partialize: (state) => ({
        day: state.day,
        hour: state.hour,
        incursionStrength: state.incursionStrength,
        containmentWards: state.containmentWards,
      }),
    }
  )
);
