/**
 * Tool Processor Tests
 *
 * Tests the processToolCall function that handles AI tool calls
 * and produces game effects (affinity changes, pending events, etc.)
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { processToolCall } from '../../../src/events/conversations/tool_processor.js';
import {
  createTestPlayer,
  createTestCharacter,
} from '../../utils/conversationTestUtils.js';
import type { Player, Person } from '../../../src/models/index.js';

describe('Tool Processor', () => {
  let player: Player;
  let character: Person;

  beforeEach(() => {
    player = createTestPlayer();
    character = createTestCharacter({
      id: 'char-1',
      firstname: 'Alice',
      affinity: 50,
      familiarity: 25,
      relationships: ['friend'],
    });
    player.r = [character];
  });

  describe('send_message', () => {
    it('should process basic send_message tool', () => {
      const result = processToolCall('send_message', {
        message: 'Hello there!',
        sentiment: 'positive',
        mood: 'happy',
      }, character, player);

      expect(result.message).toBe('Hello there!');
      expect(result.sentiment).toBe('positive');
      expect(result.mood).toBe('happy');
      expect(result.affinityChange).toBe(5); // Positive sentiment = +5
      expect(result.familiarityChange).toBe(1);
    });

    it('should apply negative affinity for negative sentiment', () => {
      const result = processToolCall('send_message', {
        message: 'I am not happy about that.',
        sentiment: 'negative',
      }, character, player);

      expect(result.affinityChange).toBe(-5);
    });

    it('should apply no affinity change for neutral sentiment', () => {
      const result = processToolCall('send_message', {
        message: 'Okay.',
        sentiment: 'neutral',
      }, character, player);

      expect(result.affinityChange).toBe(0);
    });
  });

  describe('suggest_activity', () => {
    it('should create activity invite event', () => {
      const result = processToolCall('suggest_activity', {
        message: 'Want to grab coffee?',
        sentiment: 'positive',
        activity_type: 'coffee',
        urgency: 'soon',
      }, character, player);

      expect(result.message).toBe('Want to grab coffee?');
      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('activity_invite');
      expect(result.pendingEvent?.data.activityType).toBe('coffee');
    });

    it('should set correct priority based on urgency', () => {
      const nowResult = processToolCall('suggest_activity', {
        message: 'Let\'s go now!',
        sentiment: 'positive',
        activity_type: 'walk',
        urgency: 'now',
      }, character, player);

      const laterResult = processToolCall('suggest_activity', {
        message: 'Maybe sometime?',
        sentiment: 'positive',
        activity_type: 'walk',
        urgency: 'sometime',
      }, character, player);

      expect(nowResult.pendingEvent?.priority).toBe('high');
      expect(laterResult.pendingEvent?.priority).toBe('medium');
    });

    it('should include activity costs', () => {
      const result = processToolCall('suggest_activity', {
        message: 'Want to go to a concert?',
        sentiment: 'positive',
        activity_type: 'concert',
      }, character, player);

      expect(result.pendingEvent?.data.costs).toBeDefined();
      expect(result.pendingEvent?.data.costs.energy).toBeGreaterThan(0);
      expect(result.pendingEvent?.data.costs.money).toBeGreaterThan(0);
    });

    it('should create announcement', () => {
      const result = processToolCall('suggest_activity', {
        message: 'Let\'s study together!',
        sentiment: 'positive',
        activity_type: 'study',
      }, character, player);

      expect(result.announcement).toBeDefined();
      expect(result.announcement?.title).toBe('Activity Invite');
      expect(result.announcement?.category).toBe('activity');
    });

    it('should mark for cooldown recording', () => {
      const result = processToolCall('suggest_activity', {
        message: 'Coffee?',
        sentiment: 'positive',
        activity_type: 'coffee',
      }, character, player);

      expect(result.recordForCooldown).toBe(true);
    });
  });

  describe('express_feeling', () => {
    it('should create emotional moment event', () => {
      const result = processToolCall('express_feeling', {
        message: 'I really appreciate you being there for me.',
        sentiment: 'positive',
        feeling_type: 'gratitude',
        intensity: 'moderate',
        about_player: true,
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('emotional_moment');
      expect(result.pendingEvent?.data.feelingType).toBe('gratitude');
    });

    it('should apply higher affinity for positive feelings', () => {
      const gratitudeResult = processToolCall('express_feeling', {
        message: 'Thank you so much!',
        sentiment: 'positive',
        feeling_type: 'gratitude',
        about_player: true,
      }, character, player);

      const jealousyResult = processToolCall('express_feeling', {
        message: 'I saw you with them...',
        sentiment: 'negative',
        feeling_type: 'jealousy',
      }, character, player);

      expect(gratitudeResult.affinityChange).toBeGreaterThan(0);
      expect(jealousyResult.affinityChange).toBeLessThan(0);
    });

    it('should multiply affinity based on intensity', () => {
      const subtleResult = processToolCall('express_feeling', {
        message: 'I kind of like that.',
        sentiment: 'positive',
        feeling_type: 'love',
        intensity: 'subtle',
        about_player: true,
      }, character, player);

      const intenseResult = processToolCall('express_feeling', {
        message: 'I LOVE that!',
        sentiment: 'positive',
        feeling_type: 'love',
        intensity: 'intense',
        about_player: true,
      }, character, player);

      expect(intenseResult.affinityChange).toBeGreaterThan(subtleResult.affinityChange ?? 0);
    });

    it('should set appropriate mood for feeling type', () => {
      const loveResult = processToolCall('express_feeling', {
        message: 'I love you.',
        sentiment: 'positive',
        feeling_type: 'love',
      }, character, player);

      const fearResult = processToolCall('express_feeling', {
        message: 'I am scared.',
        sentiment: 'negative',
        feeling_type: 'fear',
      }, character, player);

      expect(loveResult.mood).toBe('flirty');
      expect(fearResult.mood).toBe('worried');
    });
  });

  describe('ask_for_date', () => {
    beforeEach(() => {
      character.relationships = ['dating'];
    });

    it('should create date request event', () => {
      const result = processToolCall('ask_for_date', {
        message: 'Want to go out tonight?',
        sentiment: 'positive',
        date_type: 'romantic',
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('date_request');
      expect(result.pendingEvent?.data.dateType).toBe('romantic');
      expect(result.pendingEvent?.priority).toBe('high');
    });

    it('should include date costs by type', () => {
      const casualResult = processToolCall('ask_for_date', {
        message: 'Casual hangout?',
        sentiment: 'positive',
        date_type: 'casual',
      }, character, player);

      const fancyResult = processToolCall('ask_for_date', {
        message: 'Fancy dinner?',
        sentiment: 'positive',
        date_type: 'fancy',
      }, character, player);

      expect(fancyResult.pendingEvent?.data.costs.money).toBeGreaterThan(
        casualResult.pendingEvent?.data.costs.money
      );
    });

    it('should create romantic announcement', () => {
      const result = processToolCall('ask_for_date', {
        message: 'Go out with me?',
        sentiment: 'positive',
        date_type: 'romantic',
      }, character, player);

      expect(result.announcement?.category).toBe('romantic');
    });
  });

  describe('confess_feelings', () => {
    it('should create confession event', () => {
      const result = processToolCall('confess_feelings', {
        message: 'I have feelings for you...',
        sentiment: 'positive',
        confession_style: 'shy',
        has_been_building: true,
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('confession');
      expect(result.pendingEvent?.data.canStartDating).toBe(true);
      expect(result.pendingEvent?.priority).toBe('high');
    });

    it('should set mood based on confession style', () => {
      const shyResult = processToolCall('confess_feelings', {
        message: 'I... um...',
        sentiment: 'positive',
        confession_style: 'shy',
      }, character, player);

      const confidentResult = processToolCall('confess_feelings', {
        message: 'I like you.',
        sentiment: 'positive',
        confession_style: 'confident',
      }, character, player);

      expect(shyResult.mood).toBe('nervous');
      expect(confidentResult.mood).toBe('flirty');
    });
  });

  describe('accept_relationship', () => {
    beforeEach(() => {
      character.relationships = ['dating'];
    });

    it('should create relationship accepted event', () => {
      const result = processToolCall('accept_relationship', {
        message: 'Yes! I would love to be your girlfriend!',
        sentiment: 'positive',
        reaction_style: 'excited',
        new_relationship: 'girlfriend',
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('relationship_accepted');
      expect(result.pendingEvent?.data.newRelationship).toBe('girlfriend');
      expect(result.pendingEvent?.data.immediate).toBe(true);
    });

    it('should have high affinity boost', () => {
      const result = processToolCall('accept_relationship', {
        message: 'Yes!',
        sentiment: 'positive',
        reaction_style: 'happy',
        new_relationship: 'girlfriend',
      }, character, player);

      expect(result.affinityChange).toBe(25);
    });

    it('should not record for cooldown (acceptance has no cooldown)', () => {
      const result = processToolCall('accept_relationship', {
        message: 'Yes!',
        sentiment: 'positive',
        reaction_style: 'happy',
        new_relationship: 'girlfriend',
      }, character, player);

      expect(result.recordForCooldown).toBe(false);
    });
  });

  describe('accept_date', () => {
    it('should create date accepted event', () => {
      const result = processToolCall('accept_date', {
        message: 'I would love to!',
        sentiment: 'positive',
        date_type: 'romantic',
        suggested_time: 'tonight',
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('date_accepted');
      expect(result.pendingEvent?.data.scheduled).toBe(true);
    });

    it('should calculate trigger time based on suggested time', () => {
      const nowResult = processToolCall('accept_date', {
        message: 'Yes!',
        sentiment: 'positive',
        date_type: 'casual',
        suggested_time: 'now',
      }, character, player);

      const weekendResult = processToolCall('accept_date', {
        message: 'Yes!',
        sentiment: 'positive',
        date_type: 'casual',
        suggested_time: 'this_weekend',
      }, character, player);

      expect(weekendResult.pendingEvent?.triggersAt).toBeGreaterThan(
        nowResult.pendingEvent?.triggersAt ?? 0
      );
    });
  });

  describe('give_gift', () => {
    it('should create gift received event', () => {
      const result = processToolCall('give_gift', {
        message: 'I got you something!',
        sentiment: 'positive',
        gift_type: 'flowers',
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('gift_received');
      expect(result.pendingEvent?.data.giftType).toBe('flowers');
    });

    it('should include happiness boost in event data', () => {
      const result = processToolCall('give_gift', {
        message: 'Here!',
        sentiment: 'positive',
        gift_type: 'handmade',
      }, character, player);

      expect(result.pendingEvent?.data.happinessBoost).toBeDefined();
      expect(result.pendingEvent?.data.happinessBoost).toBeGreaterThan(0);
    });

    it('should apply player happiness stat changes', () => {
      const result = processToolCall('give_gift', {
        message: 'For you!',
        sentiment: 'positive',
        gift_type: 'experience',
      }, character, player);

      expect(result.playerStatChanges?.happiness).toBeDefined();
    });
  });

  describe('initiate_breakup', () => {
    beforeEach(() => {
      character.relationships = ['girlfriend'];
    });

    it('should create breakup event', () => {
      const result = processToolCall('initiate_breakup', {
        message: 'I think we need to talk...',
        sentiment: 'negative',
        reason: 'lost_feelings',
        tone: 'sad',
      }, character, player);

      expect(result.pendingEvent).toBeDefined();
      expect(result.pendingEvent?.type).toBe('breakup_initiated');
      expect(result.pendingEvent?.data.downgradesTo).toBe('ex');
      expect(result.pendingEvent?.data.immediate).toBe(true);
    });

    it('should have large negative affinity change', () => {
      const result = processToolCall('initiate_breakup', {
        message: 'It is over.',
        sentiment: 'negative',
        reason: 'lost_feelings',
        tone: 'cold',
      }, character, player);

      expect(result.affinityChange).toBe(-30);
    });

    it('should decrease player happiness', () => {
      const result = processToolCall('initiate_breakup', {
        message: 'Goodbye.',
        sentiment: 'negative',
        reason: 'lost_feelings',
        tone: 'sad',
      }, character, player);

      expect(result.playerStatChanges?.happiness).toBe(-20);
    });
  });

  describe('Unknown Tools', () => {
    it('should handle unknown tool gracefully', () => {
      const result = processToolCall('unknown_tool', {
        message: 'Some message',
        sentiment: 'neutral',
      }, character, player);

      expect(result.message).toBe('Some message');
      expect(result.sentiment).toBe('neutral');
    });
  });

  describe('Romantic vs Non-Romantic Context', () => {
    it('should give higher affinity for romantic relationships', () => {
      const friendCharacter = createTestCharacter({
        id: 'friend-char',
        relationships: ['friend'],
        affinity: 50,
      });

      const romanticCharacter = createTestCharacter({
        id: 'romantic-char',
        relationships: ['girlfriend'],
        affinity: 50,
      });

      const friendResult = processToolCall('suggest_activity', {
        message: 'Coffee?',
        sentiment: 'positive',
        activity_type: 'coffee',
      }, friendCharacter, player);

      const romanticResult = processToolCall('suggest_activity', {
        message: 'Coffee?',
        sentiment: 'positive',
        activity_type: 'coffee',
      }, romanticCharacter, player);

      // Romantic relationship gets higher base affinity
      expect(romanticResult.affinityChange).toBeGreaterThan(friendResult.affinityChange ?? 0);
    });
  });
});
