/**
 * Achievement collection summary tests (T011c).
 *
 * getAchievementSummary should return, per category, BOTH locked and unlocked
 * achievements with a hint + progressPercent, plus per-category completion %,
 * so a client can render a collection screen.
 */
import { describe, it, expect, beforeEach } from 'vitest';
import {
  getAchievementSummary,
  unlockAchievement,
  clearAllAchievements,
  ACHIEVEMENT_DEFINITIONS,
  type AchievementCategory,
} from '../../../src/services/retention/achievements.js';

const PLAYER = 'summary-player';

describe('getAchievementSummary collection view', () => {
  beforeEach(() => {
    clearAllAchievements();
  });

  it('returns every achievement (locked + unlocked) across categories', () => {
    const summary = getAchievementSummary(PLAYER);
    expect(summary.total).toBe(ACHIEVEMENT_DEFINITIONS.length);
    expect(summary.unlocked).toBe(0);
    expect(summary.progressPercent).toBe(0);

    const totalEntries = Object.values(summary.byCategory).reduce(
      (sum, c) => sum + c.entries.length,
      0
    );
    expect(totalEntries).toBe(ACHIEVEMENT_DEFINITIONS.length);
  });

  it('locked entries carry a hint and 0% progress; unlocked carry 100%', () => {
    const summary = getAchievementSummary(PLAYER);
    for (const cat of Object.values(summary.byCategory)) {
      for (const entry of cat.entries) {
        expect(entry.unlocked).toBe(false);
        expect(entry.progressPercent).toBe(0);
        expect(entry.hint.length).toBeGreaterThan(0);
      }
    }
  });

  it('hidden/secret locked entries get a teaser hint, not the real description', () => {
    const summary = getAchievementSummary(PLAYER);
    const secrets = summary.byCategory.secret.entries;
    expect(secrets.length).toBeGreaterThan(0);
    for (const entry of secrets) {
      if (entry.hidden && !entry.unlocked) {
        expect(entry.hint).toMatch(/secret/i);
        expect(entry.hint).not.toBe(entry.description);
      }
    }
  });

  it('reflects unlocked achievements with per-category progress percentages', () => {
    // Unlock one career achievement.
    unlockAchievement(PLAYER, 'first_job');
    const summary = getAchievementSummary(PLAYER);

    expect(summary.unlocked).toBe(1);
    expect(summary.progressPercent).toBeGreaterThan(0);

    const career = summary.byCategory.career as { total: number; unlocked: number; progressPercent: number; entries: Array<{ key: string; unlocked: boolean; progressPercent: number; hint: string }> };
    expect(career.unlocked).toBe(1);
    expect(career.progressPercent).toBe(Math.floor((1 / career.total) * 100));

    const firstJob = career.entries.find(e => e.key === 'first_job')!;
    expect(firstJob.unlocked).toBe(true);
    expect(firstJob.progressPercent).toBe(100);
    expect(firstJob.hint).toBe('');
  });

  it('every defined category appears in byCategory', () => {
    const summary = getAchievementSummary(PLAYER);
    const cats: AchievementCategory[] = [
      'life_milestone',
      'career',
      'relationship',
      'collection',
      'secret',
    ];
    for (const cat of cats) {
      expect(summary.byCategory[cat]).toBeDefined();
      expect(summary.byCategory[cat].total).toBeGreaterThan(0);
    }
  });
});
