import { describe, it, expect } from 'vitest';
import {
  ACHIEVEMENTS,
  ACHIEVEMENT_CATEGORY_COLORS,
  getAchievementsByCategory,
  isAchievementRevealed,
} from '../data/achievements';

describe('Achievement Definitions', () => {
  it('should have 24 achievements defined', () => {
    expect(Object.keys(ACHIEVEMENTS).length).toBe(24);
  });

  it('should have achievements across 5 categories', () => {
    const byCategory = getAchievementsByCategory();
    const categories = Object.keys(byCategory).sort();
    expect(categories).toEqual(['combat', 'crafting', 'magic', 'progression', 'special']);
  });

  it('should have valid structure for every achievement', () => {
    Object.values(ACHIEVEMENTS).forEach((a) => {
      expect(a.id).toBeTruthy();
      expect(a.name).toBeTruthy();
      expect(a.desc).toBeTruthy();
      expect(a.category).toBeTruthy();
      expect(a.requirement.type).toBeTruthy();
      expect(a.requirement.value).toBeGreaterThan(0);
      // At least one reward key must be present
      const rewardKeys = Object.keys(a.reward);
      expect(rewardKeys.length).toBeGreaterThan(0);
    });
  });

  it('should have category colors for all used categories', () => {
    const byCategory = getAchievementsByCategory();
    Object.keys(byCategory).forEach((cat) => {
      expect(ACHIEVEMENT_CATEGORY_COLORS[cat]).toBeDefined();
    });
  });

  it('should have hidden flag only on special category achievements', () => {
    Object.values(ACHIEVEMENTS).forEach((a) => {
      if (a.hidden) {
        expect(a.category).toBe('special');
      }
    });
  });

  it('should have exactly 2 hidden achievements', () => {
    const hidden = Object.values(ACHIEVEMENTS).filter((a) => a.hidden);
    expect(hidden.length).toBe(2); // speedRunner and perfectionist
  });
});

describe('getAchievementsByCategory', () => {
  it('should group achievements correctly', () => {
    const byCategory = getAchievementsByCategory();
    // Combat has 6 floor + 3 damage = 9
    expect(byCategory['combat'].length).toBe(9);
    // Progression has 3 pacts
    expect(byCategory['progression'].length).toBe(3);
    // Magic has 3 spells + 3 mana = 6
    expect(byCategory['magic'].length).toBe(6);
    // Crafting has 3
    expect(byCategory['crafting'].length).toBe(3);
    // Special has 3 (2 hidden + 1 survivor)
    expect(byCategory['special'].length).toBe(3);
  });

  it('should return a new object each call (no mutation)', () => {
    const result1 = getAchievementsByCategory();
    const result2 = getAchievementsByCategory();
    expect(result1).not.toBe(result2);
    expect(result1).toEqual(result2);
  });
});

describe('isAchievementRevealed', () => {
  it('should always reveal non-hidden achievements', () => {
    const nonHidden = Object.values(ACHIEVEMENTS).find((a) => !a.hidden);
    expect(nonHidden).toBeDefined();
    expect(isAchievementRevealed(nonHidden!, 0)).toBe(true);
    expect(isAchievementRevealed(nonHidden!, 999)).toBe(true);
  });

  it('should hide hidden achievements below 50% progress', () => {
    const hidden = Object.values(ACHIEVEMENTS).find((a) => a.hidden);
    expect(hidden).toBeDefined();
    // At 0% progress
    expect(isAchievementRevealed(hidden!, 0)).toBe(false);
    // At 25% progress
    expect(isAchievementRevealed(hidden!, hidden!.requirement.value * 0.25)).toBe(false);
    // At exactly 49% progress
    expect(isAchievementRevealed(hidden!, hidden!.requirement.value * 0.49)).toBe(false);
  });

  it('should reveal hidden achievements at 50% progress', () => {
    const hidden = Object.values(ACHIEVEMENTS).find((a) => a.hidden);
    expect(hidden).toBeDefined();
    // At exactly 50%
    expect(isAchievementRevealed(hidden!, hidden!.requirement.value * 0.5)).toBe(true);
    // At 75%
    expect(isAchievementRevealed(hidden!, hidden!.requirement.value * 0.75)).toBe(true);
    // At 100%
    expect(isAchievementRevealed(hidden!, hidden!.requirement.value)).toBe(true);
  });
});

describe('Achievement Rewards', () => {
  it('should have insight rewards on all achievements', () => {
    Object.values(ACHIEVEMENTS).forEach((a) => {
      expect(a.reward.insight).toBeDefined();
      expect(a.reward.insight).toBeGreaterThan(0);
    });
  });

  it('should scale rewards with difficulty', () => {
    const firstBlood = ACHIEVEMENTS['firstBlood'];
    const apexReached = ACHIEVEMENTS['apexReached'];
    expect(apexReached.reward.insight!).toBeGreaterThan(firstBlood.reward.insight!);
  });

  it('should have title rewards on top-tier achievements', () => {
    const topTiers = ['apexReached', 'spireMaster', 'tenThousandDamage', 'spellStorm', 'manaOcean', 'pactMaster', 'legendaryEnchanter'];
    topTiers.forEach((id) => {
      expect(ACHIEVEMENTS[id].reward.title).toBeDefined();
    });
  });
});
