import { describe, it, expect, beforeEach } from 'vitest';
import { createTestPlayer, createTestCharacter } from '../../utils/conversationTestUtils.js';
import { detectNPCTriggers, isAppropriateHour } from '../../../src/events/conversations/npc_initiative.js';

describe('NPC-Initiated Messages', () => {
  let player: any;
  let friend: any;
  let acquaintance: any;
  let partner: any;

  beforeEach(() => {
    friend = createTestCharacter({ firstname: 'Sara', affinity: 70, relationships: ['friend'] });
    acquaintance = createTestCharacter({ firstname: 'Bob', affinity: 20, relationships: ['acquaintance'] });
    partner = createTestCharacter({ firstname: 'Alex', affinity: 85, relationships: ['girlfriend'] });
    player = createTestPlayer();
    player.r = [friend, acquaintance, partner];
    // createTestPlayer defaults date to '2024-06-15' and hourOfDay to 14
    // Set player character birthday to match (MM-DD format)
    player.c.birthday = '06-15';
  });

  describe('trigger detection', () => {
    it('should detect birthday trigger when player birthday matches date', () => {
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(true);
    });

    it('should NOT trigger birthday for low-affinity acquaintance', () => {
      const triggers = detectNPCTriggers(player, acquaintance);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(false);
    });

    it('should detect birthday trigger for family member regardless of affinity', () => {
      const mother = createTestCharacter({ firstname: 'Mom', affinity: 30, relationships: ['mother'] });
      const triggers = detectNPCTriggers(player, mother);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(true);
    });

    it('should NOT detect birthday when date does not match', () => {
      player.date = '2024-07-01';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(false);
    });

    it('should detect time gap trigger for high-affinity character', () => {
      (friend as any).lastConversationDate = '2024-06-10';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'time_gap')).toBe(true);
    });

    it('should NOT trigger time gap for low-affinity character', () => {
      (acquaintance as any).lastConversationDate = '2024-06-10';
      const triggers = detectNPCTriggers(player, acquaintance);
      expect(triggers.some((t: any) => t.type === 'time_gap')).toBe(false);
    });

    it('should NOT trigger time gap when gap is less than 3 days', () => {
      (friend as any).lastConversationDate = '2024-06-14';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'time_gap')).toBe(false);
    });

    it('should detect morning text trigger for partner', () => {
      player.hourOfDay = 8;
      const triggers = detectNPCTriggers(player, partner);
      expect(triggers.some((t: any) => t.type === 'morning_text')).toBe(true);
    });

    it('should NOT detect morning text for non-partner', () => {
      player.hourOfDay = 8;
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'morning_text')).toBe(false);
    });

    it('should NOT detect morning text outside morning hours', () => {
      player.hourOfDay = 14;
      const triggers = detectNPCTriggers(player, partner);
      expect(triggers.some((t: any) => t.type === 'morning_text')).toBe(false);
    });

    it('should return empty triggers for dead characters', () => {
      friend.status = 'dead';
      (friend as any).lastConversationDate = '2024-06-10';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers).toHaveLength(0);
    });
  });

  describe('throttling', () => {
    it('should limit to 2 NPC-initiated messages per game day', () => {
      const state = { messagesThisDay: 0, lastDay: player.date };
      expect(state.messagesThisDay < 2).toBe(true);
      state.messagesThisDay = 2;
      expect(state.messagesThisDay < 2).toBe(false);
    });
  });

  describe('time appropriateness', () => {
    it('should not allow messages during deep night (before 7am)', () => {
      expect(isAppropriateHour(3)).toBe(false);
      expect(isAppropriateHour(6)).toBe(false);
    });

    it('should allow messages during daytime', () => {
      expect(isAppropriateHour(7)).toBe(true);
      expect(isAppropriateHour(14)).toBe(true);
      expect(isAppropriateHour(22)).toBe(true);
    });

    it('should not allow messages late at night (after 10pm)', () => {
      expect(isAppropriateHour(23)).toBe(false);
    });
  });

  describe('trigger priorities', () => {
    it('should assign highest priority to birthday triggers', () => {
      player.hourOfDay = 8;
      const triggers = detectNPCTriggers(player, partner);
      const birthday = triggers.find((t: any) => t.type === 'birthday');
      const morningText = triggers.find((t: any) => t.type === 'morning_text');
      expect(birthday).toBeDefined();
      expect(morningText).toBeDefined();
      expect(birthday!.priority).toBeGreaterThan(morningText!.priority);
    });
  });

  describe('date format handling', () => {
    it('should handle MM-DD date format (production format)', () => {
      player.date = '06-15';
      player.c.birthday = '06-15';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(true);
    });

    it('should handle YYYY-MM-DD date format (test format)', () => {
      player.date = '2024-06-15';
      player.c.birthday = '06-15';
      const triggers = detectNPCTriggers(player, friend);
      expect(triggers.some((t: any) => t.type === 'birthday')).toBe(true);
    });
  });
});
