/**
 * Achievements Service Tests
 * Tests the achievements business logic with mock implementations
 */
import { describe, it, expect, beforeEach } from 'vitest';

// Mock achievements data
const ACHIEVEMENTS = [
  { id: 'ach-1', title: 'First Steps', description: 'Create your character', category: 'milestone', diamondReward: 10 },
  { id: 'ach-2', title: 'Social Starter', description: 'Make your first friend', category: 'social', diamondReward: 15 },
  { id: 'ach-3', title: 'Hard Worker', description: 'Complete a year of work', category: 'career', moneyReward: 500 },
  { id: 'ach-4', title: 'Healthy Living', description: 'Maintain 100 health for 30 days', category: 'health', energyReward: 50 },
  { id: 'ach-5', title: 'Scholar', description: 'Graduate from college', category: 'education', diamondReward: 100 },
  { id: 'ach-6', title: 'Millionaire', description: 'Accumulate $1,000,000', category: 'finance', diamondReward: 500 },
  { id: 'ach-7', title: 'Family Person', description: 'Have 3 children', category: 'family', diamondReward: 50 },
  { id: 'ach-8', title: 'Centenarian', description: 'Live to 100 years old', category: 'milestone', diamondReward: 1000 },
];

// Mock player achievement storage
const playerAchievements = new Map<string, Set<string>>();

// Mock service functions
function getAchievements() {
  return ACHIEVEMENTS;
}

function getPlayerAchievements(playerId: string): string[] {
  if (!playerAchievements.has(playerId)) {
    playerAchievements.set(playerId, new Set());
  }
  return Array.from(playerAchievements.get(playerId)!);
}

function hasAchievement(playerId: string, achievementId: string): boolean {
  const achievements = playerAchievements.get(playerId) ?? new Set();
  return achievements.has(achievementId);
}

function unlockAchievement(playerId: string, achievementId: string) {
  if (!playerAchievements.has(playerId)) {
    playerAchievements.set(playerId, new Set());
  }

  const achievements = playerAchievements.get(playerId)!;

  if (achievements.has(achievementId)) {
    return { success: false, message: 'Already unlocked' };
  }

  const achievement = ACHIEVEMENTS.find(a => a.id === achievementId);
  if (!achievement) {
    return { success: false, message: 'Achievement not found' };
  }

  achievements.add(achievementId);

  return {
    success: true,
    achievement,
    reward: {
      diamonds: achievement.diamondReward ?? 0,
      money: achievement.moneyReward ?? 0,
      energy: achievement.energyReward ?? 0,
    },
  };
}

interface MockPlayer {
  ageYears: number;
  money: number;
  health: number;
  education: string;
  children?: unknown[];
}

function checkAchievements(playerId: string, playerState: MockPlayer): string[] {
  const newAchievements: string[] = [];
  const currentAchievements = playerAchievements.get(playerId) ?? new Set();

  // Check age milestone
  if (playerState.ageYears >= 100 && !currentAchievements.has('ach-8')) {
    newAchievements.push('ach-8');
  }

  // Check millionaire
  if (playerState.money >= 1000000 && !currentAchievements.has('ach-6')) {
    newAchievements.push('ach-6');
  }

  // Check college graduation
  if (playerState.education === 'College Graduate' && !currentAchievements.has('ach-5')) {
    newAchievements.push('ach-5');
  }

  return newAchievements;
}

describe('Achievements Service', () => {
  beforeEach(() => {
    playerAchievements.clear();
  });

  describe('getAchievements', () => {
    it('should return list of all achievements', () => {
      const achievements = getAchievements();

      expect(Array.isArray(achievements)).toBe(true);
      expect(achievements.length).toBeGreaterThan(0);
    });

    it('should have achievements with required properties', () => {
      const achievements = getAchievements();

      achievements.forEach(achievement => {
        expect(achievement).toHaveProperty('id');
        expect(achievement).toHaveProperty('title');
        expect(achievement).toHaveProperty('description');
        expect(typeof achievement.id).toBe('string');
        expect(typeof achievement.title).toBe('string');
        expect(typeof achievement.description).toBe('string');
      });
    });

    it('should have achievements with categories', () => {
      const achievements = getAchievements();
      const categories = new Set(achievements.map(a => a.category));

      expect(categories.size).toBeGreaterThan(0);
    });

    it('should have achievements with rewards', () => {
      const achievements = getAchievements();
      const achievementsWithRewards = achievements.filter(a =>
        (a.diamondReward ?? 0) > 0 ||
        (a.moneyReward ?? 0) > 0 ||
        (a.energyReward ?? 0) > 0
      );

      expect(achievementsWithRewards.length).toBeGreaterThan(0);
    });
  });

  describe('getPlayerAchievements', () => {
    it('should return empty array for new player', () => {
      const achievements = getPlayerAchievements('new-player');

      expect(Array.isArray(achievements)).toBe(true);
      expect(achievements.length).toBe(0);
    });

    it('should return unlocked achievements', () => {
      const playerId = 'test-player';
      unlockAchievement(playerId, 'ach-1');
      unlockAchievement(playerId, 'ach-2');

      const achievements = getPlayerAchievements(playerId);

      expect(achievements).toContain('ach-1');
      expect(achievements).toContain('ach-2');
    });
  });

  describe('hasAchievement', () => {
    it('should return false for unearned achievement', () => {
      const result = hasAchievement('test', 'ach-1');

      expect(result).toBe(false);
    });

    it('should return true for earned achievement', () => {
      const playerId = 'test-player';
      unlockAchievement(playerId, 'ach-1');

      const result = hasAchievement(playerId, 'ach-1');

      expect(result).toBe(true);
    });
  });

  describe('unlockAchievement', () => {
    it('should unlock new achievement', () => {
      const result = unlockAchievement('test', 'ach-1');

      expect(result.success).toBe(true);
      expect(result.achievement?.title).toBe('First Steps');
    });

    it('should return reward on unlock', () => {
      const result = unlockAchievement('test', 'ach-1');

      expect(result.reward?.diamonds).toBe(10);
    });

    it('should fail if already unlocked', () => {
      const playerId = 'test-player';
      unlockAchievement(playerId, 'ach-1');

      const result = unlockAchievement(playerId, 'ach-1');

      expect(result.success).toBe(false);
    });

    it('should fail for non-existent achievement', () => {
      const result = unlockAchievement('test', 'non-existent');

      expect(result.success).toBe(false);
    });
  });

  describe('checkAchievements', () => {
    it('should detect age milestone achievements', () => {
      const newAchievements = checkAchievements('test', {
        ageYears: 100,
        money: 0,
        health: 100,
        education: 'High School',
      });

      expect(newAchievements).toContain('ach-8');
    });

    it('should detect millionaire achievement', () => {
      const newAchievements = checkAchievements('test', {
        ageYears: 30,
        money: 1000000,
        health: 100,
        education: 'High School',
      });

      expect(newAchievements).toContain('ach-6');
    });

    it('should detect graduation achievement', () => {
      const newAchievements = checkAchievements('test', {
        ageYears: 22,
        money: 0,
        health: 100,
        education: 'College Graduate',
      });

      expect(newAchievements).toContain('ach-5');
    });

    it('should not return already earned achievements', () => {
      const playerId = 'test-player';
      unlockAchievement(playerId, 'ach-8');

      const newAchievements = checkAchievements(playerId, {
        ageYears: 100,
        money: 0,
        health: 100,
        education: 'High School',
      });

      expect(newAchievements).not.toContain('ach-8');
    });
  });

  describe('Achievement categories', () => {
    it('should have milestone achievements', () => {
      const achievements = getAchievements();
      const milestone = achievements.filter(a => a.category === 'milestone');

      expect(milestone.length).toBeGreaterThan(0);
    });

    it('should have social achievements', () => {
      const achievements = getAchievements();
      const social = achievements.filter(a => a.category === 'social');

      expect(social.length).toBeGreaterThan(0);
    });

    it('should have career achievements', () => {
      const achievements = getAchievements();
      const career = achievements.filter(a => a.category === 'career');

      expect(career.length).toBeGreaterThan(0);
    });
  });

  describe('Achievement rewards', () => {
    it('should have diamond rewards', () => {
      const achievements = getAchievements();
      const withDiamonds = achievements.filter(a => (a.diamondReward ?? 0) > 0);

      expect(withDiamonds.length).toBeGreaterThan(0);
    });

    it('should have appropriate reward scaling', () => {
      const achievements = getAchievements();

      // Harder achievements should have bigger rewards
      const centenarian = achievements.find(a => a.id === 'ach-8');
      const firstSteps = achievements.find(a => a.id === 'ach-1');

      expect(centenarian?.diamondReward).toBeGreaterThan(firstSteps?.diamondReward ?? 0);
    });
  });
});
