/**
 * Game Flow Integration Tests
 */
import { describe, it, expect, beforeEach } from 'vitest';
import { Person } from '../../src/models/Person.js';
import { Player } from '../../src/models/Player.js';

// Game flow simulation helpers
interface GameAction {
  type: string;
  payload?: any;
  expectedResult?: any;
}

function simulateGameAction(player: Player, action: GameAction): any {
  switch (action.type) {
    case 'ageUp':
      const days = action.payload?.days ?? 1;
      player.c.ageDays = (player.c.ageDays ?? 0) + days;
      if ((player.c.ageDays ?? 0) >= 365) {
        player.c.ageYears = (player.c.ageYears ?? 0) + Math.floor((player.c.ageDays ?? 0) / 365);
        player.c.ageDays = (player.c.ageDays ?? 0) % 365;
      }
      return { newAge: player.c.ageYears };

    case 'earnMoney':
      const amount = action.payload?.amount ?? 100;
      player.c.money = (player.c.money ?? 0) + amount;
      return { newBalance: player.c.money };

    case 'spendMoney':
      const cost = action.payload?.amount ?? 50;
      if ((player.c.money ?? 0) >= cost) {
        player.c.money = (player.c.money ?? 0) - cost;
        return { success: true, newBalance: player.c.money };
      }
      return { success: false, reason: 'Insufficient funds' };

    case 'useEnergy':
      const energyCost = action.payload?.amount ?? 10;
      if ((player.c.energy ?? 0) >= energyCost) {
        player.c.energy = (player.c.energy ?? 0) - energyCost;
        return { success: true, newEnergy: player.c.energy };
      }
      return { success: false, reason: 'Insufficient energy' };

    case 'restoreEnergy':
      const restore = action.payload?.amount ?? 20;
      player.c.energy = Math.min(100, (player.c.energy ?? 0) + restore);
      return { newEnergy: player.c.energy };

    case 'changeHappiness':
      const happinessChange = action.payload?.amount ?? 10;
      player.c.happiness = Math.max(0, Math.min(100, (player.c.happiness ?? 50) + happinessChange));
      return { newHappiness: player.c.happiness };

    case 'addRelationship':
      const newPerson = new Person(action.payload);
      player.r.push(newPerson);
      return { relationshipCount: player.r.length };

    case 'startSchool':
      if ((player.c.ageYears ?? 0) >= 5) {
        player.c.education = 'Elementary School';
        return { success: true, education: player.c.education };
      }
      return { success: false, reason: 'Too young' };

    case 'getJob':
      if ((player.c.ageYears ?? 0) >= 16) {
        player.c.occupation = action.payload?.job ?? 'Part-time Worker';
        return { success: true, occupation: player.c.occupation };
      }
      return { success: false, reason: 'Too young to work' };

    default:
      return { error: 'Unknown action' };
  }
}

describe('Game Flow Integration', () => {
  let player: Player;

  beforeEach(() => {
    const character = new Person({
      id: 'main-char',
      firstname: 'Test',
      lastname: 'Player',
      sex: 'male',
      ageYears: 0,
      ageDays: 0,
      status: 'alive',
      money: 0,
      diamonds: 0,
      energy: 100,
      health: 100,
      happiness: 50,
      intelligence: 50,
      prestige: 0,
    });

    player = new Player({
      userId: 'player-1',
      character: character,
      r: [],
      status: 'playing',
      date: '2024-01-01',
      hourOfDay: 8,
      season: 'winter',
    });
  });

  describe('Character lifecycle', () => {
    it('should simulate birth to childhood', () => {
      expect(player.c.ageYears).toBe(0);

      // Age to 5 years
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 5 } });

      expect(player.c.ageYears).toBe(5);
    });

    it('should simulate childhood to teen', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 13 } });

      expect(player.c.ageYears).toBe(13);
    });

    it('should simulate teen to adult', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 18 } });

      expect(player.c.ageYears).toBe(18);
    });

    it('should simulate full life', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 80 } });

      expect(player.c.ageYears).toBe(80);
    });
  });

  describe('Education flow', () => {
    it('should start elementary school at age 5', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 5 } });

      const result = simulateGameAction(player, { type: 'startSchool' });

      expect(result.success).toBe(true);
      expect(player.c.education).toBe('Elementary School');
    });

    it('should not start school before age 5', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 4 } });

      const result = simulateGameAction(player, { type: 'startSchool' });

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

    it('should progress through education levels', () => {
      const educationPath = [
        { age: 5, level: 'Elementary School' },
        { age: 11, level: 'Middle School' },
        { age: 14, level: 'High School' },
        { age: 18, level: 'College' },
      ];

      educationPath.forEach(({ age, level }) => {
        player.c.ageYears = age;
        player.c.education = level;

        expect(player.c.education).toBe(level);
        expect(player.c.ageYears).toBe(age);
      });
    });
  });

  describe('Career flow', () => {
    it('should get part-time job at 16', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 16 } });

      const result = simulateGameAction(player, {
        type: 'getJob',
        payload: { job: 'Retail Associate' },
      });

      expect(result.success).toBe(true);
      expect(player.c.occupation).toBe('Retail Associate');
    });

    it('should not get job before 16', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 15 } });

      const result = simulateGameAction(player, { type: 'getJob' });

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

    it('should earn money from job', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 18 } });
      simulateGameAction(player, { type: 'getJob', payload: { job: 'Developer' } });

      const initialMoney = player.c.money ?? 0;
      simulateGameAction(player, { type: 'earnMoney', payload: { amount: 5000 } });

      expect(player.c.money).toBe(initialMoney + 5000);
    });
  });

  describe('Resource management', () => {
    it('should manage energy throughout the day', () => {
      const initialEnergy = player.c.energy ?? 100;

      // Use energy for activities
      simulateGameAction(player, { type: 'useEnergy', payload: { amount: 30 } });
      expect(player.c.energy).toBe(initialEnergy - 30);

      // Rest to restore
      simulateGameAction(player, { type: 'restoreEnergy', payload: { amount: 20 } });
      expect(player.c.energy).toBe(initialEnergy - 10);
    });

    it('should not use more energy than available', () => {
      player.c.energy = 20;

      const result = simulateGameAction(player, { type: 'useEnergy', payload: { amount: 50 } });

      expect(result.success).toBe(false);
      expect(player.c.energy).toBe(20);
    });

    it('should cap energy at 100', () => {
      player.c.energy = 90;

      simulateGameAction(player, { type: 'restoreEnergy', payload: { amount: 50 } });

      expect(player.c.energy).toBe(100);
    });

    it('should manage money flow', () => {
      simulateGameAction(player, { type: 'earnMoney', payload: { amount: 1000 } });
      expect(player.c.money).toBe(1000);

      const spendResult = simulateGameAction(player, { type: 'spendMoney', payload: { amount: 300 } });
      expect(spendResult.success).toBe(true);
      expect(player.c.money).toBe(700);

      const failedSpend = simulateGameAction(player, { type: 'spendMoney', payload: { amount: 1000 } });
      expect(failedSpend.success).toBe(false);
      expect(player.c.money).toBe(700);
    });
  });

  describe('Relationship building', () => {
    it('should add family at birth', () => {
      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'mom', firstname: 'Mom', relationships: ['mother'], affinity: 80 },
      });

      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'dad', firstname: 'Dad', relationships: ['father'], affinity: 80 },
      });

      expect(player.r).toHaveLength(2);
    });

    it('should make friends at school', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 7 } });

      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'friend1', firstname: 'Alex', relationships: ['classmate', 'friend'], affinity: 50 },
      });

      expect(player.r).toHaveLength(1);
      expect(player.r[0].relationships).toContain('friend');
    });

    it('should build romantic relationships as adult', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 20 } });

      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'partner', firstname: 'Jordan', relationships: ['partner'], affinity: 70 },
      });

      expect(player.r[0].relationships).toContain('partner');
    });
  });

  describe('Happiness and wellbeing', () => {
    it('should increase happiness from positive events', () => {
      const initial = player.c.happiness ?? 50;

      simulateGameAction(player, { type: 'changeHappiness', payload: { amount: 20 } });

      expect(player.c.happiness).toBe(initial + 20);
    });

    it('should decrease happiness from negative events', () => {
      const initial = player.c.happiness ?? 50;

      simulateGameAction(player, { type: 'changeHappiness', payload: { amount: -30 } });

      expect(player.c.happiness).toBe(initial - 30);
    });

    it('should not exceed 100 happiness', () => {
      player.c.happiness = 90;

      simulateGameAction(player, { type: 'changeHappiness', payload: { amount: 50 } });

      expect(player.c.happiness).toBe(100);
    });

    it('should not go below 0 happiness', () => {
      player.c.happiness = 10;

      simulateGameAction(player, { type: 'changeHappiness', payload: { amount: -50 } });

      expect(player.c.happiness).toBe(0);
    });
  });

  describe('Daily routine simulation', () => {
    it('should simulate a typical day', () => {
      // Morning - start with full energy
      player.c.energy = 100;

      // Go to school/work
      simulateGameAction(player, { type: 'useEnergy', payload: { amount: 30 } });
      expect(player.c.energy).toBe(70);

      // Lunch - slight recovery
      simulateGameAction(player, { type: 'restoreEnergy', payload: { amount: 10 } });
      expect(player.c.energy).toBe(80);

      // Afternoon activities
      simulateGameAction(player, { type: 'useEnergy', payload: { amount: 20 } });
      expect(player.c.energy).toBe(60);

      // Evening - homework/chores
      simulateGameAction(player, { type: 'useEnergy', payload: { amount: 15 } });
      expect(player.c.energy).toBe(45);

      // Night - sleep recovery
      simulateGameAction(player, { type: 'restoreEnergy', payload: { amount: 55 } });
      expect(player.c.energy).toBe(100);
    });
  });

  describe('Milestone events', () => {
    it('should track first day of school', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 5 } });
      simulateGameAction(player, { type: 'startSchool' });

      expect(player.c.education).toBe('Elementary School');
    });

    it('should track first job', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 16 } });

      const result = simulateGameAction(player, {
        type: 'getJob',
        payload: { job: 'Fast Food Worker' },
      });

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

    it('should track first relationship', () => {
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 16 } });

      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'crush', firstname: 'Taylor', relationships: ['girlfriend'], affinity: 60 },
      });

      expect(player.r.length).toBe(1);
    });
  });

  describe('Multiple game sessions', () => {
    it('should persist state across simulated sessions', () => {
      // Session 1 - Birth to age 10
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 10 } });
      simulateGameAction(player, { type: 'startSchool' });
      simulateGameAction(player, {
        type: 'addRelationship',
        payload: { id: 'friend', firstname: 'Best Friend', relationships: ['friend'] },
      });

      const state1 = {
        age: player.c.ageYears,
        education: player.c.education,
        relationships: player.r.length,
      };

      // Session 2 - Continue to age 18
      simulateGameAction(player, { type: 'ageUp', payload: { days: 365 * 8 } });

      expect(player.c.ageYears).toBe(state1.age! + 8);
      expect(player.c.education).toBe(state1.education);
      expect(player.r.length).toBe(state1.relationships);
    });
  });
});
