/**
 * Question Model Tests
 */
import { describe, it, expect } from 'vitest';
import { Question, type AnswerOption } from '../../src/models/Question.js';

describe('Question Model', () => {
  describe('constructor', () => {
    it('should create a Question with minimal data', () => {
      const question = new Question({
        id: 'q-1',
        message: 'What do you want to do?',
        type: 'questionEvent',
        answers: [],
      });

      expect(question.id).toBe('q-1');
      expect(question.message).toBe('What do you want to do?');
      expect(question.type).toBe('questionEvent');
    });

    it('should create a Question with answer options', () => {
      const answers: AnswerOption[] = [
        { key: 'a', text: 'Option A' },
        { key: 'b', text: 'Option B' },
      ];

      const question = new Question({
        id: 'q-2',
        message: 'Choose an option',
        type: 'questionEvent',
        answers,
      });

      expect(question.answers).toHaveLength(2);
      expect(question.answers[0].key).toBe('a');
      expect(question.answers[1].key).toBe('b');
    });
  });

  describe('answer costs', () => {
    it('should handle options with energy costs', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Work out?',
        type: 'questionEvent',
        answers: [
          { key: 'yes', text: 'Yes', energyCost: 20 },
          { key: 'no', text: 'No' },
        ],
      });

      expect(question.answers[0].energyCost).toBe(20);
      expect(question.answers[1].energyCost).toBeUndefined();
    });

    it('should handle options with money costs', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Buy something?',
        type: 'questionEvent',
        answers: [
          { key: 'yes', text: 'Yes', moneyCost: 100 },
          { key: 'no', text: 'No' },
        ],
      });

      expect(question.answers[0].moneyCost).toBe(100);
    });

    it('should handle options with diamond costs', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Premium choice?',
        type: 'questionEvent',
        answers: [
          { key: 'premium', text: 'Premium', diamondCost: 10 },
          { key: 'free', text: 'Free' },
        ],
      });

      expect(question.answers[0].diamondCost).toBe(10);
    });

    it('should handle options with multiple costs', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Expensive choice?',
        type: 'questionEvent',
        answers: [
          { key: 'a', text: 'Costly', energyCost: 10, moneyCost: 50, diamondCost: 5 },
        ],
      });

      const answer = question.answers[0];
      expect(answer.energyCost).toBe(10);
      expect(answer.moneyCost).toBe(50);
      expect(answer.diamondCost).toBe(5);
    });
  });

  describe('character involvement', () => {
    it('should include character images', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Talk to friend?',
        type: 'questionEvent',
        answers: [{ key: 'yes', text: 'Yes' }],
        characters: [
          { id: 'char-1', firstname: 'Alice', image: 'alice.png' },
        ],
      });

      expect(question.characters).toHaveLength(1);
      expect(question.characters[0].firstname).toBe('Alice');
    });

    it('should handle multiple character images', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Group activity?',
        type: 'questionEvent',
        answers: [{ key: 'yes', text: 'Yes' }],
        characters: [
          { id: 'char-1', firstname: 'Alice' },
          { id: 'char-2', firstname: 'Bob' },
          { id: 'char-3', firstname: 'Charlie' },
        ],
      });

      expect(question.characters).toHaveLength(3);
    });

    it('should track characters involved in the question', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Social event',
        type: 'questionEvent',
        answers: [{ key: 'a', text: 'Go' }],
        characters: [
          { id: 'friend-1', firstname: 'Friend' },
        ],
      });

      expect(question.characters[0].id).toBe('friend-1');
    });
  });

  describe('question types', () => {
    it('should handle educational questions', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Study for exam?',
        type: 'education',
        answers: [
          { key: 'study', text: 'Study hard', energyCost: 30 },
          { key: 'skip', text: 'Skip studying' },
        ],
      });

      expect(question.type).toBe('education');
    });

    it('should handle career questions', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Accept promotion?',
        type: 'career',
        answers: [
          { key: 'accept', text: 'Accept' },
          { key: 'decline', text: 'Decline' },
        ],
      });

      expect(question.type).toBe('career');
    });

    it('should handle social questions', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Go to party?',
        type: 'social',
        answers: [
          { key: 'go', text: 'Go', energyCost: 20 },
          { key: 'stay', text: 'Stay home' },
        ],
      });

      expect(question.type).toBe('social');
    });

    it('should handle relationship questions', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Confess feelings?',
        type: 'relationship',
        answers: [
          { key: 'confess', text: 'Confess' },
          { key: 'wait', text: 'Wait' },
        ],
      });

      expect(question.type).toBe('relationship');
    });
  });

  describe('getAnswer method', () => {
    it('should find answer by key', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Choose?',
        type: 'questionEvent',
        answers: [
          { key: 'a', text: 'Option A' },
          { key: 'b', text: 'Option B' },
        ],
      });

      const answer = question.getAnswer('a');
      expect(answer).toBeDefined();
      expect(answer?.text).toBe('Option A');
    });

    it('should return undefined for non-existent key', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Choose?',
        type: 'questionEvent',
        answers: [{ key: 'a', text: 'A' }],
      });

      const answer = question.getAnswer('z');
      expect(answer).toBeUndefined();
    });
  });

  describe('serialization', () => {
    it('should serialize to JSON correctly', () => {
      const question = new Question({
        id: 'serialize-test',
        message: 'Test question',
        type: 'questionEvent',
        answers: [
          { key: 'a', text: 'A', energyCost: 10 },
        ],
        image: 'test.png',
      });

      const json = JSON.stringify(question);
      const parsed = JSON.parse(json);

      expect(parsed.id).toBe('serialize-test');
      expect(parsed.message).toBe('Test question');
      expect(parsed.answers).toHaveLength(1);
      expect(parsed.image).toBe('test.png');
    });
  });

  describe('answer option counts', () => {
    it('should handle 2 options', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Binary choice',
        type: 'questionEvent',
        answers: [
          { key: 'yes', text: 'Yes' },
          { key: 'no', text: 'No' },
        ],
      });

      expect(question.answers).toHaveLength(2);
    });

    it('should handle 3 options', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Triple choice',
        type: 'questionEvent',
        answers: [
          { key: 'a', text: 'A' },
          { key: 'b', text: 'B' },
          { key: 'c', text: 'C' },
        ],
      });

      expect(question.answers).toHaveLength(3);
    });

    it('should handle 4 options', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Quad choice',
        type: 'questionEvent',
        answers: [
          { key: 'a', text: 'A' },
          { key: 'b', text: 'B' },
          { key: 'c', text: 'C' },
          { key: 'd', text: 'D' },
        ],
      });

      expect(question.answers).toHaveLength(4);
    });

    it('should handle many options', () => {
      const answers: AnswerOption[] = [];
      for (let i = 0; i < 10; i++) {
        answers.push({ key: `opt-${i}`, text: `Option ${i}` });
      }

      const question = new Question({
        id: 'q-1',
        message: 'Many choices',
        type: 'questionEvent',
        answers,
      });

      expect(question.answers).toHaveLength(10);
    });
  });

  describe('image property', () => {
    it('should store question image', () => {
      const question = new Question({
        id: 'q-1',
        message: 'Question with image',
        type: 'questionEvent',
        answers: [{ key: 'a', text: 'A' }],
        image: 'question-bg.png',
      });

      expect(question.image).toBe('question-bg.png');
    });

    it('should default to empty string without image', () => {
      const question = new Question({
        id: 'q-1',
        message: 'No image',
        type: 'questionEvent',
        answers: [{ key: 'a', text: 'A' }],
      });

      expect(question.image).toBe('');
    });
  });

  describe('empty characters', () => {
    it('should default to empty array without characters', () => {
      const question = new Question({
        id: 'q-1',
        message: 'No characters',
        type: 'questionEvent',
        answers: [{ key: 'a', text: 'A' }],
      });

      expect(question.characters).toEqual([]);
    });
  });
});
