import { describe, it, expect } from 'vitest';
import { Person } from '../../../src/models/Person.js';

describe('Person', () => {
  it('should create a person with required fields', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
    });

    expect(person.id).toBe('test-id');
    expect(person.fullName).toBe('John Doe');
    expect(person.firstname).toBe('John');
    expect(person.lastname).toBe('Doe');
  });

  it('should calculate health percentage', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      health: 75,
    });

    expect(person.healthPercentage).toBe(75);
  });

  it('should clamp health percentage to 0-100', () => {
    const personOverMax = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      health: 150,
    });
    expect(personOverMax.healthPercentage).toBe(100);

    const personUnderMin = new Person({
      id: 'test-id',
      firstname: 'Jane',
      lastname: 'Doe',
      sex: 'Female',
      health: -50,
    });
    expect(personUnderMin.healthPercentage).toBe(0);
  });

  it('should have default values for optional fields', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
    });

    expect(person.status).toBe('alive');
    expect(person.mood).toBe('Calm');
    expect(person.affinity).toBe(50);
    expect(person.money).toBe(0);
    expect(person.diamonds).toBe(0);
    expect(person.health).toBe(100);
    expect(person.energy).toBe(100);
    expect(person.happiness).toBe(50);
    expect(person.intelligence).toBe(50);
    expect(person.location).toBe('home');
    expect(person.relationships).toEqual([]);
    expect(person.activities).toEqual([]);
    expect(person.items).toEqual([]);
  });

  it('should handle age properties', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      ageDays: 9125, // 25 years
      ageYears: 25,
    });

    expect(person.ageDays).toBe(9125);
    expect(person.ageYears).toBe(25);
  });

  it('should calculate ageYears from ageDays if not provided', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      ageDays: 3650, // 10 years
    });

    expect(person.ageYears).toBe(10);
  });

  it('should handle stats properly', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      health: 80,
      energy: 60,
      happiness: 70,
      intelligence: 85,
      prestige: 100,
      money: 5000,
      diamonds: 50,
    });

    expect(person.health).toBe(80);
    expect(person.energy).toBe(60);
    expect(person.happiness).toBe(70);
    expect(person.intelligence).toBe(85);
    expect(person.prestige).toBe(100);
    expect(person.money).toBe(5000);
    expect(person.diamonds).toBe(50);
  });

  it('should handle relationship-related fields', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      relationships: ['friend', 'colleague'],
      familiarity: 75,
      affinity: 80,
    });

    expect(person.relationships).toEqual(['friend', 'colleague']);
    expect(person.familiarity).toBe(75);
    expect(person.affinity).toBe(80);
  });

  it('should handle occupation and education', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      occupation: 'Engineer',
      education: 'Bachelor',
    });

    expect(person.occupation).toBe('Engineer');
    expect(person.education).toBe('Bachelor');
  });

  it('should serialize to JSON correctly', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      health: 90,
      energy: 80,
    });

    const json = person.toJSON();

    expect(json.id).toBe('test-id');
    expect(json.firstname).toBe('John');
    expect(json.lastname).toBe('Doe');
    expect(json.sex).toBe('Male');
    expect(json.health).toBe(90);
    expect(json.energy).toBe(80);
  });

  it('should handle mood states', () => {
    const moods = ['Calm', 'Stressed', 'Exhausted', 'Fulfilled', 'Depressed', 'Happy'];

    moods.forEach(mood => {
      const person = new Person({
        id: 'test-id',
        firstname: 'John',
        lastname: 'Doe',
        sex: 'Male',
        mood,
      });
      expect(person.mood).toBe(mood);
    });
  });

  it('should handle habits', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      habits: [
        { id: 'habit-1', name: 'Smoking', status: 'active' },
        { id: 'habit-2', name: 'Drinking', status: 'quitting', daysQuit: 5 },
      ],
    });

    expect(person.habits).toHaveLength(2);
    expect(person.habits[0].name).toBe('Smoking');
    expect(person.habits[1].status).toBe('quitting');
    expect(person.habits[1].daysQuit).toBe(5);
  });

  it('should handle spending habits', () => {
    const spendingTypes: Array<'frugal' | 'normal' | 'extravagant'> = ['frugal', 'normal', 'extravagant'];

    spendingTypes.forEach(spendingHabits => {
      const person = new Person({
        id: 'test-id',
        firstname: 'John',
        lastname: 'Doe',
        sex: 'Male',
        spendingHabits,
      });
      expect(person.spendingHabits).toBe(spendingHabits);
    });
  });

  it('should handle profile fields', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      bio: 'A test bio',
      interests: ['music', 'sports', 'reading'],
      traits: ['kind', 'intelligent'],
    });

    expect(person.bio).toBe('A test bio');
    expect(person.interests).toEqual(['music', 'sports', 'reading']);
    expect(person.traits).toEqual(['kind', 'intelligent']);
  });

  it('should handle children array', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'Parent',
      lastname: 'Person',
      sex: 'Female',
      children: [
        { id: 'child-1', firstname: 'Child', lastname: 'One', ageDays: 1825, ageYears: 5, sex: 'Male' },
      ],
    });

    expect(person.children).toHaveLength(1);
    expect(person.children[0].firstname).toBe('Child');
    expect(person.children[0].ageYears).toBe(5);
  });

  it('should handle physical attributes', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      braces: true,
      glasses: true,
    });

    expect(person.braces).toBe(true);
    expect(person.glasses).toBe(true);
  });

  it('should handle game loop properties', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      calcEnergy: 75,
      peakEnergy: 100,
      salary: 50000,
      location: 'work',
    });

    expect(person.calcEnergy).toBe(75);
    expect(person.peakEnergy).toBe(100);
    expect(person.salary).toBe(50000);
    expect(person.location).toBe('work');
  });

  it('should handle messaging traits', () => {
    const person = new Person({
      id: 'test-id',
      firstname: 'John',
      lastname: 'Doe',
      sex: 'Male',
      messaging_traits: {
        verbosity: 70,
        inquisitiveness: 60,
        expressiveness: 80,
        responsiveness: 75,
        openness: 65,
        emoji_usage: 40,
        formality: 50,
        response_timing: 85,
      },
    });

    expect(person.messaging_traits?.verbosity).toBe(70);
    expect(person.messaging_traits?.emoji_usage).toBe(40);
  });
});
