import { describe, it, expect, beforeEach } from 'vitest';
import { useGameStore } from '../stores/gameStore';
import { useManaStore } from '../stores/manaStore';
import { useCombatStore } from '../stores/combatStore';
import { usePrestigeStore } from '../stores/prestigeStore';
import { useUIStore } from '../stores/uiStore';
import { MAX_DAY } from '../constants';
import { resetAllStores, tickN } from './cross-module-helpers';

describe('Cross-Module: Lifecycle & Consistency', () => {
  beforeEach(resetAllStores);

  describe('full loop lifecycle', () => {
    it('should progress through multiple days without errors', () => {
      expect(() => {
        tickN(1000);
      }).not.toThrow();
    });

    it('should end the loop when day exceeds MAX_DAY', () => {
      useGameStore.setState({ day: MAX_DAY, hour: 23.9 });

      tickN(5);

      expect(useUIStore.getState().gameOver).toBe(true);
      expect(usePrestigeStore.getState().loopInsight).toBeGreaterThan(0);
    });

    it('should generate log messages during the loop', () => {
      usePrestigeStore.setState({ defeatedGuardians: [10], insight: 1000 });
      useCombatStore.setState({ currentAction: 'climb' });

      tickN(100);

      const logs = useUIStore.getState().logs;
      expect(Array.isArray(logs)).toBe(true);
    });
  });

  describe('store consistency after many ticks', () => {
    it('should keep rawMana within [0, maxMana] after many ticks', () => {
      useManaStore.setState({ rawMana: 50 });

      tickN(500);

      const mana = useManaStore.getState().rawMana;
      expect(mana).toBeGreaterThanOrEqual(0);
      expect(mana).toBeLessThanOrEqual(200);
    });

    it('should keep floorHP within [0, floorMaxHP] after many ticks', () => {
      useCombatStore.setState({ currentAction: 'climb' });

      tickN(200);

      const { floorHP, floorMaxHP } = useCombatStore.getState();
      expect(floorHP).toBeGreaterThanOrEqual(0);
      expect(floorHP).toBeLessThanOrEqual(floorMaxHP);
    });

    it('should keep currentFloor within [1, 100] after many ticks', () => {
      useCombatStore.setState({ currentAction: 'climb' });

      tickN(1000);

      const { currentFloor } = useCombatStore.getState();
      expect(currentFloor).toBeGreaterThanOrEqual(1);
      expect(currentFloor).toBeLessThanOrEqual(100);
    });

    it('should keep day within [1, MAX_DAY + 1] during normal play', () => {
      tickN(100);

      const { day } = useGameStore.getState();
      expect(day).toBeGreaterThanOrEqual(1);
      expect(day).toBeLessThanOrEqual(MAX_DAY + 1);
    });

    it('should keep hour within [0, 24) after any number of ticks', () => {
      tickN(999);

      const { hour } = useGameStore.getState();
      expect(hour).toBeGreaterThanOrEqual(0);
      expect(hour).toBeLessThan(24);
    });

    it('should keep incursionStrength within [0, 0.95]', () => {
      tickN(2000);

      const { incursionStrength } = useGameStore.getState();
      expect(incursionStrength).toBeGreaterThanOrEqual(0);
      expect(incursionStrength).toBeLessThanOrEqual(0.95);
    });
  });

  describe('pause and gameOver consistency', () => {
    it('should not change any store state when paused', () => {
      useUIStore.setState({ paused: true });
      useManaStore.setState({ rawMana: 50 });
      useCombatStore.setState({ currentFloor: 5, currentAction: 'climb' });

      const manaBefore = useManaStore.getState().rawMana;
      const floorBefore = useCombatStore.getState().currentFloor;
      const dayBefore = useGameStore.getState().day;

      tickN(10);

      expect(useManaStore.getState().rawMana).toBe(manaBefore);
      expect(useCombatStore.getState().currentFloor).toBe(floorBefore);
      expect(useGameStore.getState().day).toBe(dayBefore);
    });

    it('should not change any store state when gameOver', () => {
      useUIStore.setState({ gameOver: true });
      useManaStore.setState({ rawMana: 50 });

      const manaBefore = useManaStore.getState().rawMana;
      const dayBefore = useGameStore.getState().day;

      tickN(10);

      expect(useManaStore.getState().rawMana).toBe(manaBefore);
      expect(useGameStore.getState().day).toBe(dayBefore);
    });
  });
});
