/**
 * PlayerFactory - Creates test players at various life stages
 *
 * Factory for creating Player instances with consistent test data,
 * supporting different ages and life stage presets.
 */

import { Person, type Sex } from '../models/Person.js';
import { Player, type PlayerData } from '../models/Player.js';
import { config } from '../config.js';

export type LifeStage = 'newborn' | 'toddler' | 'child' | 'teen' | 'adult' | 'senior';

export interface PlayerFactoryOptions {
  userId?: string;
  firstname?: string;
  lastname?: string;
  sex?: Sex;
  birthday?: string;
  gameSpeed?: number;
}

// Life stage age ranges
const STAGE_AGES: Record<LifeStage, number> = {
  newborn: 0,
  toddler: 3,
  child: 8,
  teen: 15,
  adult: 25,
  senior: 65,
};

// Life stage occupation/education defaults
const STAGE_DEFAULTS: Record<LifeStage, { occupation: string; education: string }> = {
  newborn: { occupation: '', education: '' },
  toddler: { occupation: '', education: '' },
  child: { occupation: 'Student', education: 'Elementary School' },
  teen: { occupation: 'Student', education: 'High School' },
  adult: { occupation: 'Employee', education: 'College' },
  senior: { occupation: 'Retired', education: 'College' },
};

export class PlayerFactory {
  private static counter = 0;

  /**
   * Generate a unique ID for test players
   */
  private static generateId(): string {
    return `test-player-${++this.counter}-${Date.now()}`;
  }

  /**
   * Create a newborn player (age 0)
   */
  static createNewborn(options: PlayerFactoryOptions = {}): Player {
    return this.createAtAge(0, options);
  }

  /**
   * Create a player at a specific age in years
   */
  static createAtAge(ageYears: number, options: PlayerFactoryOptions = {}): Player {
    const userId = options.userId ?? this.generateId();
    const ageDays = ageYears * 365;

    // Determine life stage from age
    let stage: LifeStage = 'newborn';
    if (ageYears >= 65) stage = 'senior';
    else if (ageYears >= 18) stage = 'adult';
    else if (ageYears >= 13) stage = 'teen';
    else if (ageYears >= 5) stage = 'child';
    else if (ageYears >= 2) stage = 'toddler';

    const stageDefaults = STAGE_DEFAULTS[stage];

    // Calculate a birthday based on current date and age
    const today = new Date();
    const birthYear = today.getFullYear() - ageYears;
    const birthday =
      options.birthday ?? `${birthYear}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;

    const character = new Person({
      id: `${userId}-character`,
      firstname: options.firstname ?? 'Test',
      lastname: options.lastname ?? 'Player',
      sex: options.sex ?? 'Male',
      ageDays,
      ageYears,
      ageHours: ageDays * 24,
      birthday,
      status: 'alive',
      occupation: stageDefaults.occupation,
      education: stageDefaults.education,
      // Set reasonable defaults for stats
      health: 100,
      energy: 100,
      happiness: 50,
      intelligence: 50,
      social: 50,
      stress: 0,
      mood: 'Calm',
    });

    // Create some test relationships for dating/social events
    const relationships = PlayerFactory.createTestRelationships(userId, ageYears);

    const playerData: PlayerData = {
      userId,
      character,
      relationships,
      status: 'playing',
      controller: 'active',
      connection: 'connected',
      gameSpeed: options.gameSpeed ?? config.SPEED_DEFAULT,
      previousGameSpeed: options.gameSpeed ?? config.SPEED_DEFAULT,
    };

    return new Player(playerData);
  }

  /**
   * Create test relationships for social/dating events
   */
  private static createTestRelationships(userId: string, playerAge: number): Person[] {
    // Only create relationships for players old enough to have friends/dates
    if (playerAge < 5) return [];

    const relationships: Person[] = [];
    const relTypes = playerAge >= 13
      ? ['Friend', 'Friend', 'Classmate', 'Crush']
      : ['Friend', 'Friend', 'Sibling'];

    for (let i = 0; i < relTypes.length; i++) {
      const relType = relTypes[i];
      const isMale = Math.random() > 0.5;
      const names = isMale
        ? ['Alex', 'Jordan', 'Sam', 'Taylor', 'Chris']
        : ['Morgan', 'Casey', 'Riley', 'Jamie', 'Avery'];

      relationships.push(new Person({
        id: `${userId}-rel-${i}`,
        firstname: names[i % names.length],
        lastname: 'TestPerson',
        sex: isMale ? 'Male' : 'Female',
        ageDays: playerAge * 365 + Math.floor(Math.random() * 365 - 182),
        ageYears: playerAge + Math.floor(Math.random() * 3 - 1),
        status: 'alive',
        relationships: [relType],
        affinity: 30 + Math.floor(Math.random() * 50), // 30-80 affinity
        familiarity: 20 + Math.floor(Math.random() * 40), // 20-60 familiarity
      }));
    }

    return relationships;
  }

  /**
   * Create a player at a specific life stage
   */
  static createAtStage(stage: LifeStage, options: PlayerFactoryOptions = {}): Player {
    const ageYears = STAGE_AGES[stage];
    return this.createAtAge(ageYears, options);
  }

  /**
   * Create a player with custom Person data
   */
  static createWithPerson(
    personData: Partial<import('../models/Person.js').PersonData>,
    options: PlayerFactoryOptions = {}
  ): Player {
    const userId = options.userId ?? this.generateId();

    const character = new Person({
      id: personData.id ?? `${userId}-character`,
      firstname: personData.firstname ?? options.firstname ?? 'Test',
      lastname: personData.lastname ?? options.lastname ?? 'Player',
      sex: personData.sex ?? options.sex ?? 'Male',
      ...personData,
    });

    const playerData: PlayerData = {
      userId,
      character,
      status: 'playing',
      controller: 'active',
      connection: 'connected',
      gameSpeed: options.gameSpeed ?? config.SPEED_DEFAULT,
      previousGameSpeed: options.gameSpeed ?? config.SPEED_DEFAULT,
    };

    return new Player(playerData);
  }

  /**
   * Reset the counter (useful between tests)
   */
  static resetCounter(): void {
    this.counter = 0;
  }
}
