import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { useGameStore } from '../stores/gameStore';
import { useManaStore } from '../stores/manaStore';
import { useCombatStore } from '../stores/combatStore';
import { usePrestigeStore } from '../stores/prestigeStore';
import { useCraftingStore } from '../stores/craftingStore';
import { useAttunementStore } from '../stores/attunementStore';
import { useDisciplineStore } from '../stores/discipline-slice';
import { useUIStore } from '../stores/uiStore';

// Exact localStorage keys matching each store's persist config `name`
const ALL_STORE_KEYS = [
  'mana-loop-game-storage',
  'mana-loop-mana',
  'mana-loop-combat',
  'mana-loop-prestige',
  'mana-loop-crafting',
  'mana-loop-attunements',
  'mana-loop-discipline-store',
  'mana-loop-ui-storage',
] as const;

function clearAllPersistedState() {
  for (const key of ALL_STORE_KEYS) {
    localStorage.removeItem(key);
  }
}

/**
 * Set non-default state across ALL stores to simulate a game in progress.
 * This modifies every field that should be reset by resetGame().
 */
function setNonDefaultState() {
  // Game store: advance time
  useGameStore.setState({ day: 15, hour: 12 });

  // Mana store: add mana, unlock elements
  useManaStore.setState((s) => ({
    rawMana: 500,
    meditateTicks: 100,
    totalManaGathered: 10000,
    elements: {
      ...s.elements,
      fire: { current: 50, max: 100, baseMax: 100, unlocked: true },
      water: { current: 30, max: 100, baseMax: 100, unlocked: true },
    },
  }));

  // Combat store: change many fields
  useCombatStore.setState({
    currentFloor: 25,
    floorHP: 500,
    floorMaxHP: 2000,
    maxFloorReached: 25,
    activeSpell: 'fireBolt',
    currentAction: 'climb',
    castProgress: 0.5,
    spireMode: true,
    clearedFloors: { 1: true, 2: true },
    climbDirection: 'up' as const,
    isDescending: false,
    weaponCastProgress: { primary: 0.3 },
    comboHitCount: 5,
    floorHitCount: 10,
    meleeSwordProgress: { sword1: 0.2 },
    guardianShield: 100,
    guardianShieldMax: 200,
    guardianBarrier: 50,
    guardianBarrierMax: 100,
    totalSpellsCast: 500,
    totalDamageDealt: 9999,
    totalCraftsCompleted: 50,
  });

  // Prestige store: add insight, upgrades, pacts
  usePrestigeStore.setState({
    insight: 1000,
    totalInsight: 5000,
    loopCount: 3,
    prestigeUpgrades: { manaWell: 2, manaFlow: 1 },
    defeatedGuardians: [10, 20, 30],
    signedPacts: [10, 20],
  });

  // Attunement store: level up
  useAttunementStore.setState({
    attunements: {
      enchanter: { id: 'enchanter', active: true, level: 5, experience: 1000 },
      invoker: { id: 'invoker', active: true, level: 3, experience: 500 },
    },
  });

  // Discipline store: add disciplines and XP
  useDisciplineStore.setState({
    disciplines: {
      rawManaMastery: { id: 'rawManaMastery', xp: 500, paused: false },
    },
    activeIds: ['rawManaMastery'],
    totalXP: 500,
    concurrentLimit: 2,
    processedPerks: ['somePerk'],
  });

  // Crafting store: add designs, unlock effects, add loot
  useCraftingStore.setState((s) => ({
    designProgress: {
      designId: 'design-1',
      progress: 5,
      required: 10,
      name: 'My Design',
      equipmentType: 'basicStaff',
      effects: [{ effectId: 'spell_fireBolt', stacks: 1, actualCost: 30 }],
    },
    completedEnchantmentDesigns: [{ id: 'design-1', name: 'My Design', equipmentType: 'basicStaff', effects: [], totalCapacityCost: 30, totalStacks: 1 }],
    unlockedEffects: ['spell_fireBolt', 'spell_iceBolt'],
    unlockedRecipes: ['recipe1', 'recipe2'],
    lootInventory: {
      materials: { ironOre: 100, manaCrystalDust: 50 },
      blueprints: ['bp1', 'bp2'],
    },
  }));

  // UI store: set game over, pause
  useUIStore.setState({
    paused: true,
    gameOver: true,
    victory: true,
    logs: ['some log message'],
  });
}

// ═══════════════════════════════════════════════════════════════════════════════
// COMPREHENSIVE RESET GAME TESTS
// ═══════════════════════════════════════════════════════════════════════════════

describe('resetGame comprehensive', () => {
  beforeEach(() => {
    clearAllPersistedState();
  });

  afterEach(() => {
    clearAllPersistedState();
  });

  it('should reset ALL game store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const game = useGameStore.getState();
    expect(game.day).toBe(1);
    expect(game.hour).toBe(0);
    expect(game.incursionStrength).toBe(0);
    expect(game.containmentWards).toBe(0);
    expect(game.initialized).toBe(true);
  });

  it('should reset ALL mana store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const mana = useManaStore.getState();
    expect(mana.rawMana).toBeGreaterThanOrEqual(0);
    expect(mana.rawMana).toBeLessThanOrEqual(20); // starting mana should be small
    expect(mana.meditateTicks).toBe(0);
    expect(mana.totalManaGathered).toBe(0);
    expect(mana.elementRegen).toEqual({});

    // Only transference should be unlocked (or base elements depending on config)
    for (const [key, elem] of Object.entries(mana.elements)) {
      // Fire and water should NOT be unlocked (they were unlocked by setNonDefaultState)
      if (key === 'fire' || key === 'water') {
        // After reset, these should be locked (not unlocked)
        // The initial state only has certain elements unlocked
        expect(elem.current).toBeGreaterThanOrEqual(0);
        expect(elem.max).toBeGreaterThan(0);
      }
    }
  });

  it('should reset ALL combat store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const combat = useCombatStore.getState();
    expect(combat.currentFloor).toBe(1);
    expect(combat.maxFloorReached).toBe(1);
    expect(combat.activeSpell).toBe('manaBolt');
    expect(combat.currentAction).toBe('meditate');
    expect(combat.castProgress).toBe(0);

    // These fields should also be reset but might be missed by resetCombat:
    expect(combat.spireMode).toBe(false);
    expect(combat.clearedFloors).toEqual({});
    expect(combat.climbDirection).toBeNull();
    expect(combat.weaponCastProgress).toEqual({});
    expect(combat.comboHitCount).toBe(0);
    expect(combat.floorHitCount).toBe(0);
    expect(combat.meleeSwordProgress).toEqual({});
    expect(combat.guardianShield).toBe(0);
    expect(combat.guardianShieldMax).toBe(0);
    expect(combat.guardianBarrier).toBe(0);
    expect(combat.guardianBarrierMax).toBe(0);
    expect(combat.totalSpellsCast).toBe(0);
    expect(combat.totalDamageDealt).toBe(0);
    expect(combat.totalCraftsCompleted).toBe(0);
  });

  it('should reset ALL prestige store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const prestige = usePrestigeStore.getState();
    expect(prestige.insight).toBe(0);
    expect(prestige.totalInsight).toBe(0);
    expect(prestige.loopCount).toBe(0);
    expect(prestige.prestigeUpgrades).toEqual({});
    expect(prestige.defeatedGuardians).toEqual([]);
    expect(prestige.signedPacts).toEqual([]);
    expect(prestige.pactRitualFloor).toBeNull();
    expect(prestige.pactRitualProgress).toBe(0);
  });

  it('should reset ALL attunement store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const att = useAttunementStore.getState();
    // Should only have enchanter at level 1
    expect(Object.keys(att.attunements).length).toBe(1);
    expect(att.attunements.enchanter).toBeDefined();
    expect(att.attunements.enchanter.level).toBe(1);
    expect(att.attunements.enchanter.experience).toBe(0);
    expect(att.attunements.enchanter.active).toBe(true);
    // Invoker should not be present
    expect(att.attunements.invoker).toBeUndefined();
  });

  it('should reset ALL discipline store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const disc = useDisciplineStore.getState();
    expect(disc.disciplines).toEqual({});
    expect(disc.activeIds).toEqual([]);
    expect(disc.totalXP).toBe(0);
    expect(disc.processedPerks).toEqual([]);
  });

  it('should reset ALL crafting store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const crafting = useCraftingStore.getState();
    expect(crafting.designProgress).toBeNull();
    expect(crafting.designProgress2).toBeNull();
    expect(crafting.completedEnchantmentDesigns).toEqual([]);
    expect(crafting.unlockedEffects).toEqual([]);
    expect(crafting.unlockedRecipes).toEqual([]);
    expect(crafting.lootInventory.materials).toEqual({});
    expect(crafting.lootInventory.blueprints).toEqual([]);

    // Should still have the starting equipment
    expect(Object.keys(crafting.equipmentInstances).length).toBe(3); // staff, shirt, shoes
    expect(crafting.equippedInstances.mainHand).not.toBeNull();
    expect(crafting.equippedInstances.body).not.toBeNull();
    expect(crafting.equippedInstances.feet).not.toBeNull();
  });

  it('should reset ALL UI store fields to initial values', () => {
    setNonDefaultState();
    useGameStore.getState().resetGame();

    const ui = useUIStore.getState();
    expect(ui.paused).toBe(false);
    expect(ui.gameOver).toBe(false);
    expect(ui.victory).toBe(false);
    expect(ui.logs.length).toBe(1); // fresh game starts with one log message
  });

  it('should clear all localStorage keys and not leave stale data', () => {
    setNonDefaultState();

    // First, force all stores to persist by calling setState on each
    // (simulating what happens during normal gameplay)
    const gameState = useGameStore.getState();
    useGameStore.setState({ day: gameState.day });

    useGameStore.getState().resetGame();

    // After reset, localStorage should contain the reset state, not the old state
    const combatRaw = localStorage.getItem('mana-loop-combat');
    if (combatRaw) {
      const combatParsed = JSON.parse(combatRaw);
      expect(combatParsed.state.currentFloor).toBe(1);
    }

    const manaRaw = localStorage.getItem('mana-loop-mana');
    if (manaRaw) {
      const manaParsed = JSON.parse(manaRaw);
      expect(manaParsed.state.totalManaGathered).toBe(0);
    }
  });
});
