/**
 * Person Model Tests
 */
import { describe, it, expect, beforeEach } from 'vitest';
import { Person, type PersonData } from '../../src/models/Person';

describe('Person Model', () => {
  describe('constructor', () => {
    it('should create a Person with minimal data', () => {
      const person = new Person({ id: 'test-1', firstname: 'John' });
      expect(person.id).toBe('test-1');
      expect(person.firstname).toBe('John');
    });

    it('should create a Person with full data', () => {
      const data: PersonData = {
        id: 'test-2',
        firstname: 'Jane',
        lastname: 'Doe',
        sex: 'female',
        ageYears: 25,
        ageDays: 100,
        birthday: '1998-05-15',
        status: 'alive',
        mood: 75,
        health: 90,
        energy: 80,
        happiness: 85,
        intelligence: 70,
        prestige: 50,
        money: 10000,
        diamonds: 100,
      };
      const person = new Person(data);

      expect(person.id).toBe('test-2');
      expect(person.firstname).toBe('Jane');
      expect(person.lastname).toBe('Doe');
      expect(person.sex).toBe('female');
      expect(person.ageYears).toBe(25);
      expect(person.ageDays).toBe(100);
      expect(person.birthday).toBe('1998-05-15');
      expect(person.status).toBe('alive');
      expect(person.mood).toBe(75);
      expect(person.health).toBe(90);
      expect(person.energy).toBe(80);
      expect(person.happiness).toBe(85);
      expect(person.intelligence).toBe(70);
      expect(person.prestige).toBe(50);
      expect(person.money).toBe(10000);
      expect(person.diamonds).toBe(100);
    });

    it('should set default values for optional properties', () => {
      const person = new Person({ id: 'test-3' });
      expect(person.status).toBe('alive');
      expect(person.relationships).toEqual([]);
      expect(person.activities).toEqual([]);
      expect(person.interests).toEqual([]);
      expect(person.traits).toEqual([]);
    });
  });

  describe('fullName', () => {
    it('should return full name with first and last name', () => {
      const person = new Person({ id: '1', firstname: 'John', lastname: 'Smith' });
      expect(person.fullName).toBe('John Smith');
    });

    it('should return first and last name (lastname may be undefined)', () => {
      // Note: Person requires lastname in PersonData but constructor sets it from data
      const person = new Person({ id: '1', firstname: 'John', lastname: '', sex: 'Male' });
      expect(person.fullName).toBe('John ');
    });
  });

  describe('age calculations', () => {
    it('should calculate age correctly from years and days', () => {
      const person = new Person({ id: '1', ageYears: 25, ageDays: 180 });
      expect(person.ageYears).toBe(25);
      expect(person.ageDays).toBe(180);
    });

    it('should handle age 0', () => {
      const person = new Person({ id: '1', ageYears: 0, ageDays: 30 });
      expect(person.ageYears).toBe(0);
      expect(person.ageDays).toBe(30);
    });
  });

  describe('stats', () => {
    it('should have stats within valid ranges', () => {
      const person = new Person({
        id: '1',
        mood: 100,
        health: 100,
        energy: 100,
        happiness: 100,
        intelligence: 100,
        prestige: 1000,
      });

      expect(person.mood).toBeLessThanOrEqual(100);
      expect(person.health).toBeLessThanOrEqual(100);
      expect(person.energy).toBeLessThanOrEqual(100);
      expect(person.happiness).toBeLessThanOrEqual(100);
      expect(person.intelligence).toBeLessThanOrEqual(100);
    });

    it('should allow negative money', () => {
      const person = new Person({ id: '1', money: -500 });
      expect(person.money).toBe(-500);
    });
  });

  describe('relationships', () => {
    it('should store relationship types', () => {
      const person = new Person({
        id: '1',
        relationships: ['friend', 'classmate'],
      });
      expect(person.relationships).toContain('friend');
      expect(person.relationships).toContain('classmate');
    });

    it('should handle romantic relationships', () => {
      const person = new Person({
        id: '1',
        relationships: ['girlfriend'],
      });
      expect(person.relationships).toContain('girlfriend');
    });

    it('should handle family relationships', () => {
      const person = new Person({
        id: '1',
        relationships: ['mother', 'father', 'sibling'],
      });
      expect(person.relationships).toHaveLength(3);
    });
  });

  describe('activities', () => {
    it('should store activity records', () => {
      const person = new Person({
        id: '1',
        activities: [
          { id: 'act-1', title: 'Piano' },
          { id: 'act-2', title: 'Soccer' },
        ],
      });
      expect(person.activities).toHaveLength(2);
    });

    it('should handle empty activities', () => {
      const person = new Person({ id: '1' });
      expect(person.activities).toEqual([]);
    });
  });

  describe('traits and interests', () => {
    it('should store personality traits', () => {
      const person = new Person({
        id: '1',
        traits: ['outgoing', 'creative', 'ambitious'],
      });
      expect(person.traits).toContain('outgoing');
      expect(person.traits).toContain('creative');
      expect(person.traits).toContain('ambitious');
    });

    it('should store interests', () => {
      const person = new Person({
        id: '1',
        interests: ['music', 'sports', 'reading'],
      });
      expect(person.interests).toContain('music');
      expect(person.interests).toContain('sports');
      expect(person.interests).toContain('reading');
    });
  });

  describe('serialization', () => {
    it('should serialize to JSON correctly', () => {
      const data: PersonData = {
        id: 'serialize-test',
        firstname: 'Test',
        lastname: 'User',
        sex: 'male',
        ageYears: 30,
      };
      const person = new Person(data);
      const json = JSON.stringify(person);
      const parsed = JSON.parse(json);

      expect(parsed.id).toBe('serialize-test');
      expect(parsed.firstname).toBe('Test');
      expect(parsed.lastname).toBe('User');
    });
  });

  describe('education', () => {
    it('should track current education level', () => {
      const person = new Person({
        id: '1',
        education: 'High School',
        currentEducation: { school: 'Lincoln High', grade: 10 },
      });
      expect(person.education).toBe('High School');
    });

    it('should handle no education', () => {
      const person = new Person({ id: '1', firstname: 'Test', lastname: '', sex: 'Male' });
      expect(person.education).toBe(''); // defaults to empty string
    });
  });

  describe('occupation', () => {
    it('should track current job', () => {
      const person = new Person({
        id: '1',
        occupation: 'Software Engineer',
      });
      expect(person.occupation).toBe('Software Engineer');
    });
  });

  describe('affinity', () => {
    it('should track relationship affinity', () => {
      const person = new Person({
        id: '1',
        affinity: 75,
      });
      expect(person.affinity).toBe(75);
    });

    it('should default affinity to 50', () => {
      const person = new Person({ id: '1', firstname: 'Test', lastname: '', sex: 'Male' });
      expect(person.affinity).toBe(50); // defaults to 50
    });
  });

  describe('compatibility', () => {
    it('should store compatibility score', () => {
      const person = new Person({
        id: '1',
        compatibilityScore: 85,
      });
      expect(person.compatibilityScore).toBe(85);
    });
  });

  describe('bio', () => {
    it('should store character bio', () => {
      const person = new Person({
        id: '1',
        bio: 'A friendly person who loves to help others.',
      });
      expect(person.bio).toBe('A friendly person who loves to help others.');
    });
  });

  describe('image', () => {
    it('should store avatar image URL', () => {
      const person = new Person({
        id: '1',
        image: 'https://example.com/avatar.png',
      });
      expect(person.image).toBe('https://example.com/avatar.png');
    });
  });
});
