/**
 * Full Lifecycle Tests
 *
 * Tests that simulate a complete player life from birth to death,
 * automatically responding to all events with random choices.
 */

import { describe, it, expect } from 'vitest';
import { HeadlessGame, PlayerFactory } from '../../src/testing/index.js';

describe('Full Lifecycle Tests', () => {
  describe('HeadlessGame', () => {
    it('should create a newborn player by default', () => {
      const game = new HeadlessGame();

      expect(game.player).toBeDefined();
      expect(game.player.c.ageYears).toBe(0);
      expect(game.player.c.status).toBe('alive');
      expect(game.player.status).toBe('playing');
      expect(game.player.controller).toBe('active');
    });

    it('should create player at specified age', () => {
      const game = new HeadlessGame({ startAge: 25 });

      expect(game.player.c.ageYears).toBe(25);
    });

    it('should create player at specified life stage', () => {
      const game = new HeadlessGame({ startStage: 'teen' });

      expect(game.player.c.ageYears).toBe(15);
    });

    it('should advance time by ticks', async () => {
      const game = new HeadlessGame();
      const initialTicks = game.player.ticks;

      await game.tick(100);

      expect(game.player.ticks).toBeGreaterThan(initialTicks);
    });

    it('should advance time by minutes', async () => {
      const game = new HeadlessGame();

      await game.advanceMinutes(60);

      // After 60 minutes, hourOfDay should have advanced
      expect(game.player.ticks).toBe(60);
    });

    it('should advance time by hours', async () => {
      const game = new HeadlessGame();

      await game.advanceHours(1);

      expect(game.player.ticks).toBe(60);
    });

    it('should advance time by days', async () => {
      const game = new HeadlessGame();

      await game.advanceDays(1);

      expect(game.player.ticks).toBe(24 * 60);
    });

    it('should advance to a specific age', async () => {
      const game = new HeadlessGame({ autoRespond: true, startAge: 4 });

      await game.advanceToAge(5);

      expect(game.player.c.ageYears).toBeGreaterThanOrEqual(5);
    });

    it('should trigger birthday events', async () => {
      const game = new HeadlessGame({ autoRespond: true });

      // Advance to age 1
      await game.advanceToAge(1);

      // Check that birthday event was triggered
      const events = game.getEvents();
      const birthdayEvents = events.filter(e => e.event.id.includes('birthday'));

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

    it('should collect events during simulation', async () => {
      const game = new HeadlessGame({ autoRespond: true, startAge: 2 });

      await game.advanceToAge(3);

      const stats = game.getStats();
      expect(stats.events).toBeGreaterThan(0);
    });

    it('characterization: should produce at least one event or question by age 1', async () => {
      const game = new HeadlessGame({ autoRespond: true });

      await game.advanceToAge(1);

      const stats = game.getStats();
      expect(stats.events + stats.questions).toBeGreaterThan(0);
    });

    it('should provide game summary', async () => {
      const game = new HeadlessGame({ autoRespond: true, startAge: 4 });

      await game.advanceToAge(5);

      const summary = game.getSummary();

      expect(summary.playerId).toBeDefined();
      expect(summary.playerName).toBe('Test Player');
      expect(summary.status).toBe('alive');
      expect(summary.endAge).toBeGreaterThanOrEqual(5);
      expect(summary.eventsCount).toBeGreaterThanOrEqual(0);
    });
  });

  describe('Lifecycle Simulation', () => {
    it('should simulate childhood progression (age 5)', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'random',
        startAge: 4,
      });

      await game.advanceToAge(5);

      expect(game.player.c.ageYears).toBeGreaterThanOrEqual(5);
      expect(game.player.c.status).toBe('alive');

      const summary = game.getSummary();
      expect(summary.totalDays).toBeGreaterThanOrEqual(4 * 365);
    });

    it('should simulate into adolescence (age 14)', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'random',
        startAge: 12,
      });

      await game.advanceToAge(14);

      expect(game.player.c.ageYears).toBeGreaterThanOrEqual(14);
      expect(game.player.c.status).toBe('alive');
    });

    it('should simulate into adulthood (age 21)', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'random',
        startAge: 18,
      });

      await game.advanceToAge(21);

      expect(game.player.c.ageYears).toBeGreaterThanOrEqual(21);
    }, 20000);

    it('should support bounded end-of-life simulation', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        startAge: 45,
        maxTicksPerAdvance: 2_000_000,
      });

      await game.advanceToEnd(46);

      expect(
        game.player.c.status === 'dead' || game.player.c.ageYears >= 46
      ).toBe(true);

      const summary = game.getSummary();
      expect(summary.endAge).toBeGreaterThanOrEqual(45);
    }, 20000);
  });

  describe('PlayerFactory', () => {
    it('should create a newborn', () => {
      const player = PlayerFactory.createNewborn();

      expect(player.c.ageYears).toBe(0);
      expect(player.c.ageDays).toBe(0);
    });

    it('should create player at specific age', () => {
      const player = PlayerFactory.createAtAge(25);

      expect(player.c.ageYears).toBe(25);
      expect(player.c.ageDays).toBe(25 * 365);
    });

    it('should create player at life stage', () => {
      const teen = PlayerFactory.createAtStage('teen');
      const adult = PlayerFactory.createAtStage('adult');
      const senior = PlayerFactory.createAtStage('senior');

      expect(teen.c.ageYears).toBe(15);
      expect(adult.c.ageYears).toBe(25);
      expect(senior.c.ageYears).toBe(65);
    });

    it('should accept custom player options', () => {
      const player = PlayerFactory.createNewborn({
        firstname: 'Alice',
        lastname: 'Johnson',
        sex: 'Female',
      });

      expect(player.c.firstname).toBe('Alice');
      expect(player.c.lastname).toBe('Johnson');
      expect(player.c.sex).toBe('Female');
    });

    it('should assign appropriate occupation for age', () => {
      const child = PlayerFactory.createAtStage('child');
      const teen = PlayerFactory.createAtStage('teen');
      const adult = PlayerFactory.createAtStage('adult');
      const senior = PlayerFactory.createAtStage('senior');

      expect(child.c.occupation).toBe('Student');
      expect(teen.c.occupation).toBe('Student');
      expect(adult.c.occupation).toBe('Employee');
      expect(senior.c.occupation).toBe('Retired');
    });
  });

  describe('AutoResponder', () => {
    it('should respond to questions with random strategy', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'random',
        startAge: 4,
      });

      await game.advanceToAge(5);

      // If any questions were asked, they should be answered
      const questions = game.getQuestions();
      const pendingQuestions = questions.filter(q => q.pending);

      // All questions should be answered (none pending)
      expect(pendingQuestions.length).toBe(0);
    });

    it('should respond to questions with first strategy', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'first',
        logResponses: false,
        startAge: 2,
      });

      await game.advanceToAge(3);

      const responseLog = game.getResponseLog();
      // All responses should have selected the first option (index 0)
      for (const entry of responseLog) {
        // First strategy always selects index 0
        expect(entry).toBeDefined();
      }
    });

    it('should respond to questions with last strategy', async () => {
      const game = new HeadlessGame({
        autoRespond: true,
        responseStrategy: 'last',
        logResponses: false,
        startAge: 2,
      });

      await game.advanceToAge(3);

      const responseLog = game.getResponseLog();
      expect(responseLog).toBeDefined();
    });
  });

  describe('Milestone Events', () => {
    it('should track time progression during early days', async () => {
      const game = new HeadlessGame({ autoRespond: true });

      // Advance a few days
      await game.advanceDays(3);

      // Time should have advanced
      expect(game.player.ticks).toBe(3 * 24 * 60);
      expect(game.player.c.ageDays).toBeGreaterThan(0);
    });

    it('should trigger age milestone events', async () => {
      const game = new HeadlessGame({ autoRespond: true, startAge: 4 });

      await game.advanceToAge(5);

      expect(game.hasEvent('birthday_5')).toBe(true);
    });
  });
});
