import { describe, it, expect, vi, beforeEach } from 'vitest';

// ─── Test: DebugTab barrel export ─────────────────────────────────────────────
// Verifies that the DebugTab component is properly exported from the barrel
// and that all section components are importable.

describe('DebugTab module structure', () => {
  it('exports DebugTab from barrel index', async () => {
    const mod = await import('./DebugTab');
    expect(mod.DebugTab).toBeDefined();
    expect(typeof mod.DebugTab).toBe('function');
  }, 30000);

  it('exports GameStateDebugSection', async () => {
    const mod = await import('./DebugTab/GameStateDebugSection');
    expect(mod.GameStateDebugSection).toBeDefined();
    expect(typeof mod.GameStateDebugSection).toBe('function');
  });

  it('exports DisciplineDebugSection', async () => {
    const mod = await import('./DebugTab/DisciplineDebugSection');
    expect(mod.DisciplineDebugSection).toBeDefined();
    expect(typeof mod.DisciplineDebugSection).toBe('function');
  });

  it('exports AttunementDebugSection', async () => {
    const mod = await import('./DebugTab/AttunementDebugSection');
    expect(mod.AttunementDebugSection).toBeDefined();
    expect(typeof mod.AttunementDebugSection).toBe('function');
  });

  it('exports ElementDebugSection', async () => {
    const mod = await import('./DebugTab/ElementDebugSection');
    expect(mod.ElementDebugSection).toBeDefined();
    expect(typeof mod.ElementDebugSection).toBe('function');
  });

  it('exports GolemDebugSection', async () => {
    const mod = await import('./DebugTab/GolemDebugSection');
    expect(mod.GolemDebugSection).toBeDefined();
    expect(typeof mod.GolemDebugSection).toBe('function');
  });

  it('exports PactDebugSection', async () => {
    const mod = await import('./DebugTab/PactDebugSection');
    expect(mod.PactDebugSection).toBeDefined();
    expect(typeof mod.PactDebugSection).toBe('function');
  });

  it('exports SpireDebugSection', async () => {
    const mod = await import('./DebugTab/SpireDebugSection');
    expect(mod.SpireDebugSection).toBeDefined();
    expect(typeof mod.SpireDebugSection).toBe('function');
  });

  it('exports AchievementDebugSection', async () => {
    const mod = await import('./DebugTab/AchievementDebugSection');
    expect(mod.AchievementDebugSection).toBeDefined();
    expect(typeof mod.AchievementDebugSection).toBe('function');
  });
});

// ─── Test: Barrel export includes DebugTab ────────────────────────────────────

describe('Tab barrel export', () => {
  it('includes DebugTab in the tabs index', async () => {
    const mod = await import('@/components/game/tabs');
    expect(mod.DebugTab).toBeDefined();
    expect(typeof mod.DebugTab).toBe('function');
  });
});

// ─── Test: Store interactions used by DebugTab sections ───────────────────────

describe('GameStateDebugSection store interactions', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('resetGame action is callable', () => {
    const mockReset = vi.fn();
    // Simulate what GameStateDebugSection does on reset
    mockReset();
    expect(mockReset).toHaveBeenCalledTimes(1);
  });

  it('gatherMana action is callable N times for bulk add', () => {
    const mockGather = vi.fn();
    const amount = 100;
    for (let i = 0; i < amount; i++) {
      mockGather();
    }
    expect(mockGather).toHaveBeenCalledTimes(amount);
  });

  it('togglePause action is callable', () => {
    const mockToggle = vi.fn();
    mockToggle();
    expect(mockToggle).toHaveBeenCalledTimes(1);
  });

});

describe('DisciplineDebugSection store interactions', () => {
  it('activate action is callable', () => {
    const mockActivate = vi.fn();
    mockActivate('meditation');
    expect(mockActivate).toHaveBeenCalledWith('meditation');
  });

  it('deactivate action is callable', () => {
    const mockDeactivate = vi.fn();
    mockDeactivate('meditation');
    expect(mockDeactivate).toHaveBeenCalledWith('meditation');
  });

  it('XP can be added to discipline via setState', () => {
    const disciplines: Record<string, { xp: number; paused: boolean }> = {
      meditation: { xp: 0, paused: false },
    };
    const id = 'meditation';
    const amount = 100;
    disciplines[id] = { ...disciplines[id], xp: disciplines[id].xp + amount };
    expect(disciplines[id].xp).toBe(100);
  });
});

describe('AttunementDebugSection store interactions', () => {
  it('debugUnlockAttunement is callable', () => {
    const mockUnlock = vi.fn();
    mockUnlock('invoker');
    expect(mockUnlock).toHaveBeenCalledWith('invoker');
  });

  it('addAttunementXP is callable', () => {
    const mockAddXP = vi.fn();
    mockAddXP('enchanter', 100);
    expect(mockAddXP).toHaveBeenCalledWith('enchanter', 100);
  });
});

describe('ElementDebugSection store interactions', () => {
  it('unlockElement is callable with zero cost', () => {
    const mockUnlock = vi.fn();
    mockUnlock('fire', 0);
    expect(mockUnlock).toHaveBeenCalledWith('fire', 0);
  });

  it('addElementMana is callable', () => {
    const mockAdd = vi.fn();
    mockAdd('fire', 10, 50);
    expect(mockAdd).toHaveBeenCalledWith('fire', 10, 50);
  });
});

describe('GolemDebugSection store interactions', () => {
  it('addGolemDesign is callable', () => {
    const mockAdd = vi.fn();
    mockAdd({ id: 'test', name: 'Test', coreId: 'basic', frameId: 'earth', mindCircuitId: 'simple', enchantmentIds: [], selectedManaTypes: [], selectedSpells: [] });
    expect(mockAdd).toHaveBeenCalled();
  });

  it('toggleGolemLoadoutEntry is callable', () => {
    const mockToggle = vi.fn();
    mockToggle('test-design');
    expect(mockToggle).toHaveBeenCalledWith('test-design');
  });
});

describe('PactDebugSection store interactions', () => {
  it('addSignedPact is callable', () => {
    const mockAdd = vi.fn();
    mockAdd(10);
    expect(mockAdd).toHaveBeenCalledWith(10);
  });

  it('removePact is callable', () => {
    const mockRemove = vi.fn();
    mockRemove(10);
    expect(mockRemove).toHaveBeenCalledWith(10);
  });

  it('debugSetSignedPacts is callable', () => {
    const mockSet = vi.fn();
    mockSet([10, 20, 30]);
    expect(mockSet).toHaveBeenCalledWith([10, 20, 30]);
  });
});

describe('SpireDebugSection store interactions', () => {
  it('enterSpireMode is callable', () => {
    const mockEnter = vi.fn();
    mockEnter();
    expect(mockEnter).toHaveBeenCalledTimes(1);
  });

  it('exitSpireMode is callable', () => {
    const mockExit = vi.fn();
    mockExit();
    expect(mockExit).toHaveBeenCalledTimes(1);
  });

  it('setMaxFloorReached is callable', () => {
    const mockSet = vi.fn();
    mockSet(50);
    expect(mockSet).toHaveBeenCalledWith(50);
  });
});

describe('AchievementDebugSection store interactions', () => {
  it('can set all achievements as unlocked via setState', () => {
    const allIds = ['firstBlood', 'floorClimber'];
    const newState = {
      achievements: {
        unlocked: allIds,
        progress: Object.fromEntries(allIds.map(id => [id, 100])),
      },
    };
    expect(newState.achievements.unlocked).toEqual(allIds);
    expect(Object.keys(newState.achievements.progress)).toEqual(allIds);
  });

  it('can reset all achievements via setState', () => {
    const newState = {
      achievements: {
        unlocked: [],
        progress: {},
      },
    };
    expect(newState.achievements.unlocked).toEqual([]);
    expect(newState.achievements.progress).toEqual({});
  });
});

// ─── Test: DebugTab component displayName ─────────────────────────────────────

describe('DebugTab component metadata', () => {
  it('DebugTab has correct displayName', async () => {
    const { DebugTab } = await import('./DebugTab');
    expect(DebugTab.displayName).toBe('DebugTab');
  });

  it('GameStateDebugSection has correct displayName', async () => {
    const { GameStateDebugSection } = await import('./DebugTab/GameStateDebugSection');
    expect(GameStateDebugSection.displayName).toBe('GameStateDebugSection');
  });

  it('DisciplineDebugSection has correct displayName', async () => {
    const { DisciplineDebugSection } = await import('./DebugTab/DisciplineDebugSection');
    expect(DisciplineDebugSection.displayName).toBe('DisciplineDebugSection');
  });

  it('AttunementDebugSection has correct displayName', async () => {
    const { AttunementDebugSection } = await import('./DebugTab/AttunementDebugSection');
    expect(AttunementDebugSection.displayName).toBe('AttunementDebugSection');
  });

  it('ElementDebugSection has correct displayName', async () => {
    const { ElementDebugSection } = await import('./DebugTab/ElementDebugSection');
    expect(ElementDebugSection.displayName).toBe('ElementDebugSection');
  });

  it('GolemDebugSection has correct displayName', async () => {
    const { GolemDebugSection } = await import('./DebugTab/GolemDebugSection');
    expect(GolemDebugSection.displayName).toBe('GolemDebugSection');
  });

  it('PactDebugSection has correct displayName', async () => {
    const { PactDebugSection } = await import('./DebugTab/PactDebugSection');
    expect(PactDebugSection.displayName).toBe('PactDebugSection');
  });

  it('SpireDebugSection has correct displayName', async () => {
    const { SpireDebugSection } = await import('./DebugTab/SpireDebugSection');
    expect(SpireDebugSection.displayName).toBe('SpireDebugSection');
  });

  it('AchievementDebugSection has correct displayName', async () => {
    const { AchievementDebugSection } = await import('./DebugTab/AchievementDebugSection');
    expect(AchievementDebugSection.displayName).toBe('AchievementDebugSection');
  });
});

// ─── Test: File size limits ───────────────────────────────────────────────────
// Note: 400-line limit is enforced by pre-commit hook (check-file-size.js).
// These tests verify the source files are importable; line count enforcement
// is handled by the hook, not by runtime tests.

describe('File size limits (400 lines max)', () => {
  it('DebugTab.tsx is importable and under 400 lines (enforced by pre-commit hook)', async () => {
    const fs = await import('fs');
    const path = await import('path');
    const filePath = path.join(__dirname, 'DebugTab.tsx');
    const content = fs.readFileSync(filePath, 'utf-8');
    const lines = content.split('\n').length;
    expect(lines).toBeLessThan(400);
  });

  it('GameStateDebugSection.tsx is under 400 lines', async () => {
    const fs = await import('fs');
    const path = await import('path');
    const filePath = path.join(__dirname, 'DebugTab', 'GameStateDebugSection.tsx');
    const content = fs.readFileSync(filePath, 'utf-8');
    const lines = content.split('\n').length;
    expect(lines).toBeLessThan(400);
  });

  it('DisciplineDebugSection.tsx is under 400 lines', async () => {
    const fs = await import('fs');
    const path = await import('path');
    const filePath = path.join(__dirname, 'DebugTab', 'DisciplineDebugSection.tsx');
    const content = fs.readFileSync(filePath, 'utf-8');
    const lines = content.split('\n').length;
    expect(lines).toBeLessThan(400);
  });

  it('PactDebugSection.tsx is under 400 lines', async () => {
    const fs = await import('fs');
    const path = await import('path');
    const filePath = path.join(__dirname, 'DebugTab', 'PactDebugSection.tsx');
    const content = fs.readFileSync(filePath, 'utf-8');
    const lines = content.split('\n').length;
    expect(lines).toBeLessThan(400);
  });
});
