/**
 * Friend Hangout Events
 *
 * 12 friend-initiated events with real gameplay tradeoffs.
 * Friends feel like real people making demands on your time and resources.
 *
 * Realtime events (function-based, checked each hour):
 * - friendCoffeeInvite: Friend invites you for coffee (energy -10, money -$8, affinity +5)
 * - friendHelpMoving: Friend needs help moving (energy -30, affinity +8)
 * - friendToughTime: Friend going through tough time (energy -15, affinity +10)
 * - friendBirthday: Friend's birthday party (gift cost vs affinity)
 * - friendGossipChoice: Friend shares gossip about another friend
 * - friendDecayWarning: "Haven't hung out" affinity decay prevention
 * - friendConcertInvite: Friend invites you to a concert/event
 * - friendLendMoney: Friend asks to borrow money
 *
 * Fast mode events (class-based, for deep progression):
 * - BestFriendMilestone: Best friends milestone (affinity > 80)
 * - FriendBetrayal: Multi-stage betrayal (confront/forgive/distance → follow-up 1 week later)
 * - FriendInCrisis: Multi-stage crisis (support → follow-up 2 weeks later)
 * - GroupTrip: Multi-stage road trip (plan → trip events → return)
 * - FriendshipEnding: Friendship ending (affinity < -20)
 */

import { Player } from '../../models/Player.js';
import { Person } from '../../models/Person.js';
import {
  createMessageEvent,
  createQuestionEvent,
  checkProbability,
  modifyStat,
  BaseEvent,
  EventConfig,
  EventResult,
  AnswerOption,
  createAnswerOption,
} from '../base.js';
import { pickVariant } from '../../utils/textVariations.js';

// =============================================================================
// Helper: Find eligible friends
// =============================================================================

/**
 * Get friends from player.r who have 'friend' relationship or affinity > 20.
 * Filters to alive people only and respects cooldown (7 game-days).
 */
function getEligibleFriends(player: Player, cooldownDays: number = 7): Person[] {
  if (!player.r || player.r.length === 0) return [];

  return player.r.filter((person) => {
    if (person.status !== 'alive') return false;

    const isFriend =
      (person.relationships ?? []).includes('friend') ||
      (person.affinity ?? 0) > 20;

    if (!isFriend) return false;

    // Check cooldown: use lastFriendEventDay stored on person
    const lastHangout = (person as any).lastFriendEventDay as number | undefined;
    if (lastHangout !== undefined) {
      const daysSince = (player.dayOfYear ?? 0) - lastHangout;
      // Handle year boundary
      const adjustedDays = daysSince < 0 ? daysSince + 365 : daysSince;
      if (adjustedDays < cooldownDays) return false;
    }

    return true;
  });
}

/**
 * Pick a random friend from eligible list, optionally requiring minimum affinity
 */
function pickRandomFriend(player: Player, cooldownDays: number = 7, minAffinity?: number): Person | null {
  const friends = getEligibleFriends(player, cooldownDays);
  const filtered = minAffinity !== undefined
    ? friends.filter((f) => (f.affinity ?? 0) >= minAffinity)
    : friends;
  if (filtered.length === 0) return null;
  return filtered[Math.floor(Math.random() * filtered.length)];
}

/**
 * Mark a friend as recently interacted with (sets cooldown)
 */
function markFriendInteraction(person: Person, dayOfYear: number): void {
  (person as any).lastFriendEventDay = dayOfYear;
}

/**
 * Schedule a follow-up message via oneTimeEvents on the player character.
 * Uses dayOfYear offset to calculate the target date string.
 */
function scheduleFollowUp(
  player: Player,
  id: string,
  daysFromNow: number,
  hour: number,
  message: string
): void {
  // Calculate target date from dayOfYear
  let targetDayOfYear = (player.dayOfYear ?? 1) + daysFromNow;
  if (targetDayOfYear > 365) targetDayOfYear -= 365;

  // Convert dayOfYear to MM-DD date string (using 2022 base like PlayerSession)
  const baseDate = new Date(2022, 0, 1);
  const targetDate = new Date(baseDate);
  targetDate.setDate(targetDate.getDate() + targetDayOfYear - 1);
  const month = String(targetDate.getMonth() + 1).padStart(2, '0');
  const day = String(targetDate.getDate()).padStart(2, '0');
  const dateStr = `${month}-${day}`;

  player.c.oneTimeEvents = player.c.oneTimeEvents ?? [];
  player.c.oneTimeEvents.push({
    id,
    date: dateStr,
    hour,
    message,
  });
}

// =============================================================================
// Realtime Events (function-based)
// =============================================================================

/**
 * Friend invites you for coffee
 * Accept: energy -10, money -$8, affinity +5, happiness +3
 * Decline: affinity -2
 */
export function friendCoffeeInvite(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendCoffeeInvite';
  const friend = pickRandomFriend(player, 7, 30);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 14 &&
    friend !== null &&
    checkProbability(5000);

  if (!check || !friend) return null;

  const coffeeVariants = [
    `${friend.firstname} texts you: "Hey, want to grab coffee? My treat... just kidding, you're paying half!"`,
    `${friend.firstname} sends you a message: "Coffee? I found this new place I've been dying to try."`,
    `${friend.firstname} calls: "I'm bored. Let's get coffee and catch up!"`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(coffeeVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption('Sure, let\'s catch up!', 'yes', 10, 0, 8),
        createAnswerOption('Rain check, I\'m tired', 'no'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

/**
 * Friend needs help moving
 * Help: energy -30, affinity +8, happiness +2
 * Decline: affinity -5, happiness -2 (guilt)
 */
export function friendHelpMoving(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendHelpMoving';
  const friend = pickRandomFriend(player, 7, 40);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 18 &&
    friend !== null &&
    (player.c.energy ?? 100) >= 40 &&
    checkProbability(8000);

  if (!check || !friend) return null;

  const movingVariants = [
    `${friend.firstname} calls you in a panic: "I'm moving this weekend and my other helpers bailed. Can you help? I'll buy pizza!"`,
    `${friend.firstname} texts: "Hey I hate to ask, but I need help moving on Saturday. I'll owe you big time!"`,
    `${friend.firstname} shows up looking stressed: "My new place is ready but I have no one to help me move. Please?"`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(movingVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption('Of course, I\'ll be there!', 'yes', 30),
        createAnswerOption('Sorry, I can\'t this weekend', 'no'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

/**
 * Friend going through a tough time
 * Listen: energy -15 (emotional labor), affinity +10, social +3
 * "I'm busy": affinity -3
 */
export function friendToughTime(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendToughTime';
  const friend = pickRandomFriend(player);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 12 &&
    friend !== null &&
    checkProbability(6000);

  if (!check || !friend) return null;

  const toughTimeVariants = [
    `${friend.firstname} calls you late at night, clearly upset. "Can we talk? I'm going through something really hard right now."`,
    `${friend.firstname} sends a long text that ends with: "I don't know who else to turn to right now."`,
    `You notice ${friend.firstname} has been posting sad things online. They reply to your check-in: "Yeah... I'm not doing great."`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(toughTimeVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption('I\'m here for you, tell me everything', 'listen', 15),
        createAnswerOption('Send a supportive text back', 'text', 5),
        createAnswerOption('I\'m busy right now, sorry', 'ignore'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

/**
 * Friend's birthday - gift cost vs affinity
 * Great gift ($50): affinity +10 | Small gift ($15): affinity +5 | No gift: affinity +2 | Forget: affinity -8
 */
export function friendBirthday(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendBirthday';
  const friend = pickRandomFriend(player);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 8 &&
    friend !== null &&
    checkProbability(6000);

  if (!check || !friend) return null;

  // Scale gift cost with friendship depth
  const affinity = friend.affinity ?? 50;
  const expensiveGift = affinity > 60 ? 100 : 50;
  const cheapGift = affinity > 60 ? 30 : 15;

  return createQuestionEvent(
    fname,
    `It's ${friend.firstname}'s birthday! They're having a party this weekend. What do you want to do?`,
    player,
    true,
    {
      answerOptions: [
        createAnswerOption(`Buy a great gift ($${expensiveGift})`, 'expensive', 5, 0, expensiveGift),
        createAnswerOption(`Get something small ($${cheapGift})`, 'cheap', 5, 0, cheapGift),
        createAnswerOption('Just show up, no gift', 'nogift', 5),
        createAnswerOption('Skip the party', 'skip'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

/**
 * Friend shares gossip about mutual acquaintance
 * Engage: social +2, 10% chance target finds out (affinity -5 with target)
 * Shut it down: social -1 but trustworthy reputation
 */
export function friendGossipChoice(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendGossipChoice';
  const friends = getEligibleFriends(player);

  // Need at least 2 friends for gossip
  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 12 &&
    friends.length >= 2 &&
    checkProbability(7000);

  if (!check || friends.length < 2) return null;

  const gossiper = friends[0];
  const target = friends[1];

  return createQuestionEvent(
    fname,
    `${gossiper.firstname} pulls you aside: "Don't tell anyone, but I heard ${target.firstname} has been talking behind your back. What do you want to do?"`,
    player,
    true,
    {
      answerOptions: [
        createAnswerOption('Confront them directly', 'confront'),
        createAnswerOption('Engage in the gossip', 'spread'),
        createAnswerOption('Keep it to yourself', 'quiet'),
        createAnswerOption('Tell them you don\'t want to hear gossip', 'refuse'),
      ],
      characters: [
        { id: gossiper.id, firstname: gossiper.firstname, lastname: gossiper.lastname, image: gossiper.image },
        { id: target.id, firstname: target.firstname, lastname: target.lastname, image: target.image },
      ],
    }
  );
}

/**
 * "Haven't hung out" decay prevention
 * Triggers when a friend's affinity is decaying (10-30 range)
 * Plan something: choose activity | Acknowledge: affinity continues to decay
 */
export function friendDecayWarning(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendDecayWarning';

  // Find a friend whose affinity is between 10-30 (decaying range)
  const decliningFriend = (player.r ?? []).find((p) => {
    if (p.status !== 'alive') return false;
    const isFriend = (p.relationships ?? []).includes('friend');
    if (!isFriend) return false;
    const affinity = p.affinity ?? 0;
    return affinity >= 10 && affinity <= 30;
  });

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 10 &&
    decliningFriend !== null &&
    decliningFriend !== undefined &&
    checkProbability(4000);

  if (!check || !decliningFriend) return null;

  const decayVariants = [
    `You realize you haven't hung out with ${decliningFriend.firstname} in a while. They seem distant lately. Should you reach out?`,
    `It hits you that you and ${decliningFriend.firstname} haven't talked in ages. You miss how things used to be.`,
    `${decliningFriend.firstname} liked an old photo of yours. It reminds you that you haven't connected in a long time.`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(decayVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption('Call them and make plans', 'call', 5),
        createAnswerOption('Send a quick text', 'text'),
        createAnswerOption('They\'ll be fine', 'ignore'),
      ],
      characters: [{
        id: decliningFriend.id,
        firstname: decliningFriend.firstname,
        lastname: decliningFriend.lastname,
        image: decliningFriend.image,
      }],
    }
  );
}

/**
 * Friend invites you to a concert/event
 * Go: money -$30-100, energy -20, happiness +10, affinity +5, chance to meet new people
 * Skip: affinity -3, FOMO happiness -2
 */
export function friendConcertInvite(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendConcertInvite';
  const friend = pickRandomFriend(player);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 14 &&
    friend !== null &&
    checkProbability(6000);

  if (!check || !friend) return null;

  const events = [
    { name: 'a concert', cost: 60 },
    { name: 'a comedy show', cost: 40 },
    { name: 'a sports game', cost: 80 },
    { name: 'a food festival', cost: 30 },
    { name: 'an art exhibit', cost: 25 },
  ];
  const event = events[Math.floor(Math.random() * events.length)];

  const concertVariants = [
    `${friend.firstname} is excited: "I got tickets to ${event.name}! Want to come? Tickets are $${event.cost} each."`,
    `${friend.firstname} texts you a screenshot of tickets to ${event.name}: "You in? $${event.cost} a person."`,
    `${friend.firstname} won't stop talking about ${event.name} coming to town: "We HAVE to go. It's $${event.cost} each."`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(concertVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption(`Yes, let's go! ($${event.cost})`, 'yes', 20, 0, event.cost),
        createAnswerOption('Sounds fun but I\'ll pass', 'no'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

/**
 * Friend asks to borrow money
 * Tests friendship boundaries with financial pressure
 */
export function friendLendMoney(player: Player, _type: string = 'check'): EventResult {
  const fname = 'friendLendMoney';
  const friend = pickRandomFriend(player);

  const check =
    !player.events.has(fname) &&
    player.c.ageYears >= 16 &&
    friend !== null &&
    player.money >= 100 &&
    checkProbability(8000);

  if (!check || !friend) return null;

  const amount = Math.floor(Math.random() * 4 + 1) * 50; // $50-$200

  const lendVariants = [
    `${friend.firstname} awkwardly asks: "Hey... this is embarrassing, but could I borrow $${amount}? I promise I'll pay you back next month."`,
    `${friend.firstname} pulls you aside: "I'm in a tight spot. Could you lend me $${amount}? I'll get it back to you ASAP."`,
    `${friend.firstname} calls sounding stressed: "I hate asking, but I'm short $${amount}. Can you help me out?"`,
  ];

  return createQuestionEvent(
    fname,
    pickVariant(lendVariants),
    player,
    true,
    {
      answerOptions: [
        createAnswerOption(`Lend them $${amount}`, 'lend', 0, 0, amount),
        createAnswerOption('Offer half the amount', 'half', 0, 0, Math.floor(amount / 2)),
        createAnswerOption('Sorry, I can\'t right now', 'decline'),
      ],
      characters: [{ id: friend.id, firstname: friend.firstname, lastname: friend.lastname, image: friend.image }],
    }
  );
}

// =============================================================================
// Fast Mode Events (class-based)
// =============================================================================

/**
 * Best Friends Milestone - triggered when affinity > 80
 * Unlock "bestfriend" relationship tag, +5% to positive outcomes when involved
 */
export class BestFriendMilestone extends BaseEvent {
  readonly id = 'bestFriendMilestone';

  getConfig(): EventConfig {
    return {
      minAge: 8,
      maxAge: 100,
      baseChance: 0.0005,
      triggerType: 'conditional',
    };
  }

  checkConditions(player: Player): boolean {
    if (player.askedQuestions.has(this.id)) return false;

    // Need a friend with affinity > 80 who isn't already a bestfriend
    return (player.r ?? []).some((p) =>
      p.status === 'alive' &&
      (p.relationships ?? []).includes('friend') &&
      !(p.relationships ?? []).includes('bestfriend') &&
      (p.affinity ?? 0) > 80
    );
  }

  getQuestion(player?: Player): string {
    const bestFriend = (player?.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        !(p.relationships ?? []).includes('bestfriend') &&
        (p.affinity ?? 0) > 80
    );
    const name = bestFriend?.firstname ?? 'your friend';
    return `You and ${name} have become incredibly close. You realize they're your best friend. Want to make it official with matching friendship bracelets?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Best friends forever!', 'yes', 0, 0, 20),
      createAnswerOption('We\'re close but that\'s a bit much', 'no'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const bestFriend = (player.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        !(p.relationships ?? []).includes('bestfriend') &&
        (p.affinity ?? 0) > 80
    );

    if (!bestFriend) {
      return { type: 'messageEvent', message: 'The moment has passed.' };
    }

    if (selectedOption === 0) {
      bestFriend.affinity = modifyStat(bestFriend.affinity, 10, -100, 100);
      player.c.happiness = modifyStat(player.c.happiness, 15);
      player.c.energy = modifyStat(player.c.energy, 5);
      player.money = Math.max(0, player.money - 20);
      markFriendInteraction(bestFriend, player.dayOfYear);

      // Add 'bestfriend' to relationships — unlocks best friend perks
      bestFriend.relationships = bestFriend.relationships ?? [];
      if (!bestFriend.relationships.includes('bestfriend')) {
        bestFriend.relationships.push('bestfriend');
      }

      return {
        type: 'messageEvent',
        message: `You and ${bestFriend.firstname} are now officially best friends! You got matching bracelets and spent the whole day together. ${bestFriend.firstname} will now help with your events and boost positive outcomes when involved.`,
        moneyCost: 20,
        affinityChange: 10,
      };
    } else {
      return {
        type: 'messageEvent',
        message: `You appreciate ${bestFriend.firstname} but decided to keep things as they are. The friendship is still strong.`,
      };
    }
  }
}

/**
 * Friend Betrayal - Multi-stage event over 1 week
 *
 * Stage 1: "{name} told others about something you shared in confidence"
 *   → confront, forgive, or distance
 *
 * Stage 2 (1 week later, scheduled via oneTimeEvents):
 *   - Confronted: They apologize (affinity recovers to -10) or double down (friendship ends)
 *   - Forgave: Trust partially restored (affinity -15), but lingering doubt
 *   - Distanced: They notice and reach out OR accept distance (friendship slowly dies)
 */
export class FriendBetrayal extends BaseEvent {
  readonly id = 'friendBetrayal';

  getConfig(): EventConfig {
    return {
      minAge: 14,
      maxAge: 100,
      baseChance: 0.0003,
      triggerType: 'conditional',
    };
  }

  checkConditions(player: Player): boolean {
    if (player.askedQuestions.has(this.id)) return false;

    // Need a friend with moderate affinity (40-70)
    return (player.r ?? []).some(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) >= 40 &&
        (p.affinity ?? 0) <= 70
    );
  }

  getQuestion(player?: Player): string {
    const friend = (player?.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) >= 40 &&
        (p.affinity ?? 0) <= 70
    );
    const name = friend?.firstname ?? 'A friend';
    return `You discover that ${name} told others about something you shared in confidence. Several people have mentioned it. How do you respond?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Confront them directly', 'confront'),
      createAnswerOption('Forgive them and move on', 'forgive'),
      createAnswerOption('Distance yourself quietly', 'distance'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const friend = (player.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) >= 40 &&
        (p.affinity ?? 0) <= 70
    );

    if (!friend) {
      return { type: 'messageEvent', message: 'You decided to move on.' };
    }

    const name = friend.firstname;

    if (selectedOption === 0) {
      // Confront — immediate tension, schedule follow-up in 7 days
      friend.affinity = modifyStat(friend.affinity, -20, -100, 100);
      player.c.stress = modifyStat(player.c.stress, 15);
      player.c.happiness = modifyStat(player.c.happiness, -10);

      // Stage 2: 50/50 apologize or double down
      const apologizes = Math.random() < 0.5;
      if (apologizes) {
        scheduleFollowUp(
          player,
          `friendBetrayal_stage2_${friend.id}`,
          7,
          12,
          `${name} came to you and genuinely apologized for breaking your trust. "I was wrong, and I'm sorry." The friendship feels like it can recover.`
        );
      } else {
        scheduleFollowUp(
          player,
          `friendBetrayal_stage2_${friend.id}`,
          7,
          12,
          `${name} doubled down when you confronted them: "If you can't handle the truth, that's your problem." The friendship is over.`
        );
        // Schedule the friendship removal after the message
        friend.affinity = modifyStat(friend.affinity, -30, -100, 100);
      }

      return {
        type: 'messageEvent',
        message: `You confronted ${name} about breaking your confidence. It was tense. They said they'd think about what you said. The next week will tell...`,
        affinityChange: -20,
      };
    } else if (selectedOption === 1) {
      // Forgive — trust partially restored but with doubt
      friend.affinity = modifyStat(friend.affinity, -15, -100, 100);
      player.c.happiness = modifyStat(player.c.happiness, -5);

      scheduleFollowUp(
        player,
        `friendBetrayal_stage2_${friend.id}`,
        7,
        12,
        `A week after forgiving ${name}, things feel mostly normal but there's a lingering doubt. You find yourself being more careful about what you share.`
      );

      return {
        type: 'messageEvent',
        message: `You told ${name} you forgive them, but the trust isn't fully there anymore. Time will tell if the friendship recovers.`,
        affinityChange: -15,
      };
    } else {
      // Distance — they may or may not notice
      friend.affinity = modifyStat(friend.affinity, -10, -100, 100);
      player.c.happiness = modifyStat(player.c.happiness, -5);

      const theyReachOut = Math.random() < 0.4;
      if (theyReachOut) {
        scheduleFollowUp(
          player,
          `friendBetrayal_stage2_${friend.id}`,
          7,
          18,
          `${name} noticed you've been distant and reached out: "Hey, is everything okay between us? I feel like something's off." Maybe there's still hope.`
        );
      } else {
        scheduleFollowUp(
          player,
          `friendBetrayal_stage2_${friend.id}`,
          7,
          18,
          `${name} accepted the distance. You haven't heard from them in a week. The friendship is slowly dying.`
        );
        friend.affinity = modifyStat(friend.affinity, -10, -100, 100);
      }

      return {
        type: 'messageEvent',
        message: `You quietly distanced yourself from ${name}. You stopped initiating conversations and declined invitations. Sometimes silence speaks loudest.`,
        affinityChange: -10,
      };
    }
  }
}

/**
 * Friend in Crisis - Multi-stage support event
 *
 * Stage 1: "{name} is going through something serious and needs support"
 *   → Visit them / Call / Send text / Give space
 *
 * Stage 2 (2 weeks later, scheduled via oneTimeEvents):
 *   - Visited: They thank you deeply, friendship strengthened
 *   - Called: They appreciated it, moderate gratitude
 *   - Texted: They say thanks, still struggling
 *   - Space: They're still struggling and felt alone
 */
export class FriendInCrisis extends BaseEvent {
  readonly id = 'friendInCrisis';

  getConfig(): EventConfig {
    return {
      minAge: 14,
      maxAge: 100,
      baseChance: 0.0004,
      triggerType: 'conditional',
    };
  }

  checkConditions(player: Player): boolean {
    if (player.askedQuestions.has(this.id)) return false;

    return (player.r ?? []).some(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) > 30
    );
  }

  getQuestion(player?: Player): string {
    const friend = (player?.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) > 30
    );
    const name = friend?.firstname ?? 'Your friend';

    const crises = [
      `${name} just lost their job and doesn't know what to do.`,
      `${name} is dealing with a family emergency and needs support.`,
      `${name} just went through a bad breakup and is devastated.`,
      `${name} failed an important exam and is questioning everything.`,
    ];
    return crises[Math.floor(Math.random() * crises.length)] + ' How do you want to help?';
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Visit them with food and support ($30)', 'visit', 20, 0, 30),
      createAnswerOption('Call and talk it through', 'call', 10),
      createAnswerOption('Send a supportive text', 'text'),
      createAnswerOption('Give them space', 'space'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const friend = (player.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) > 30
    );

    if (!friend) {
      return { type: 'messageEvent', message: 'You hoped things worked out.' };
    }

    const name = friend.firstname;

    if (selectedOption === 0) {
      // Visit with care package — best outcome
      friend.affinity = modifyStat(friend.affinity, 15, -100, 100);
      player.c.energy = modifyStat(player.c.energy, -20);
      player.money = Math.max(0, player.money - 30);
      player.c.happiness = modifyStat(player.c.happiness, 5);
      player.c.stress = modifyStat(player.c.stress, 10);
      markFriendInteraction(friend, player.dayOfYear);

      // Stage 2: deep gratitude follow-up
      scheduleFollowUp(
        player,
        `friendCrisis_stage2_${friend.id}`,
        14,
        12,
        `${name} called to thank you again for being there during their crisis. "I don't know what I would have done without you." Your friendship has never been stronger.`
      );

      return {
        type: 'messageEvent',
        message: `You showed up at ${name}'s door with food and comfort. You spent hours together. ${name} broke down crying and said they were so grateful to have you.`,
        energyCost: 20,
        moneyCost: 30,
        affinityChange: 15,
      };
    } else if (selectedOption === 1) {
      // Phone support
      friend.affinity = modifyStat(friend.affinity, 8, -100, 100);
      player.c.energy = modifyStat(player.c.energy, -10);

      scheduleFollowUp(
        player,
        `friendCrisis_stage2_${friend.id}`,
        14,
        12,
        `${name} texted: "Thanks for listening the other week. Things are getting a little better." They appreciated you being there, even if it was just a phone call.`
      );

      return {
        type: 'messageEvent',
        message: `You called ${name} and talked for a couple hours. They appreciated having someone to vent to. You could hear the relief in their voice.`,
        energyCost: 10,
        affinityChange: 8,
      };
    } else if (selectedOption === 2) {
      // Text message
      friend.affinity = modifyStat(friend.affinity, 3, -100, 100);

      scheduleFollowUp(
        player,
        `friendCrisis_stage2_${friend.id}`,
        14,
        18,
        `${name} is still struggling. They mentioned to a mutual friend that they wished you'd been more present. A text wasn't quite enough.`
      );

      return {
        type: 'messageEvent',
        message: `You sent ${name} a thoughtful message. They thanked you but seemed to need more than words right now.`,
        affinityChange: 3,
      };
    } else {
      // Give space — negative outcome
      friend.affinity = modifyStat(friend.affinity, -5, -100, 100);

      scheduleFollowUp(
        player,
        `friendCrisis_stage2_${friend.id}`,
        14,
        18,
        `${name} has been distant since their crisis. They confided in someone else instead. You wonder if you should have been there when they needed you.`
      );

      return {
        type: 'messageEvent',
        message: `You decided to give ${name} space. You told yourself they'd reach out if they really needed you. But the silence feels heavy.`,
        affinityChange: -5,
      };
    }
  }
}

/**
 * Group Trip - Multi-stage road trip event
 *
 * Stage 1: "Your friend group wants to go on a road trip this weekend"
 *   → Join ($200, 2 days of energy drain) or skip
 *
 * Stage 2 (if joined, 1 day later): Trip events — bonding, drama, adventure
 * Stage 3 (2 days later): Return home — exhausted but happy, or drama fallout
 */
export class GroupTrip extends BaseEvent {
  readonly id = 'groupTrip';

  getConfig(): EventConfig {
    return {
      minAge: 16,
      maxAge: 100,
      baseChance: 0.0003,
      triggerType: 'conditional',
    };
  }

  checkConditions(player: Player): boolean {
    if (player.askedQuestions.has(this.id)) return false;

    // Need at least 2 friends for a group trip
    const friendCount = (player.r ?? []).filter(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) > 20
    ).length;
    return friendCount >= 2 && player.money >= 200;
  }

  getQuestion(_player?: Player): string {
    return 'Your friend group wants to go on a road trip this weekend! It would be two days of adventure, but it\'ll cost about $200 for gas, food, and activities. Are you in?';
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('I\'m in! Let\'s go!', 'join', 20, 0, 200),
      createAnswerOption('Sounds amazing but I can\'t afford it', 'skip'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    if (selectedOption === 0) {
      // Join the trip
      player.money = Math.max(0, player.money - 200);
      player.c.energy = modifyStat(player.c.energy, -20);
      player.c.happiness = modifyStat(player.c.happiness, 10);

      // Boost affinity with all friends going on the trip
      const tripFriends = (player.r ?? []).filter(
        (p) =>
          p.status === 'alive' &&
          (p.relationships ?? []).includes('friend') &&
          (p.affinity ?? 0) > 20
      );
      const names: string[] = [];
      for (const f of tripFriends.slice(0, 4)) {
        f.affinity = modifyStat(f.affinity, 5, -100, 100);
        markFriendInteraction(f, player.dayOfYear);
        names.push(f.firstname);
      }
      const nameList = names.join(', ');

      // Stage 2: Trip bonding event (1 day later)
      const bondingEvents = [
        `On the road trip, everyone sang along to terrible music and you laughed until your sides hurt. You and ${nameList} shared stories you've never told anyone.`,
        `The road trip took an unexpected detour to an amazing viewpoint. You and ${nameList} watched the sunset together in comfortable silence. Best spontaneous moment ever.`,
        `The road trip included a stop at a random town festival. You and ${nameList} danced like nobody was watching. The locals loved it.`,
      ];
      scheduleFollowUp(
        player,
        `groupTrip_stage2`,
        1,
        14,
        bondingEvents[Math.floor(Math.random() * bondingEvents.length)]
      );

      // Stage 3: Return home (2 days later) — drama or great memories
      const hasDrama = Math.random() < 0.25;
      if (hasDrama) {
        scheduleFollowUp(
          player,
          `groupTrip_stage3`,
          2,
          10,
          `You're back from the road trip. There was a bit of drama — someone got annoyed about sleeping arrangements and things got awkward. But overall, you made great memories. You're exhausted though.`
        );
      } else {
        scheduleFollowUp(
          player,
          `groupTrip_stage3`,
          2,
          10,
          `You're back from the road trip! Everyone had an amazing time. You're exhausted but your heart is full. The group chat is already planning the next one.`
        );
      }

      return {
        type: 'messageEvent',
        message: `You packed your bags and hit the road with ${nameList}! The adventure begins. Two days of friendship, spontaneity, and no responsibilities.`,
        moneyCost: 200,
        energyCost: 20,
      };
    } else {
      // Skip the trip
      player.c.happiness = modifyStat(player.c.happiness, -5);

      // FOMO follow-up
      scheduleFollowUp(
        player,
        `groupTrip_fomo`,
        2,
        18,
        'Your friends are posting photos from the road trip and it looks like they had an incredible time. You can\'t help but feel like you missed out.'
      );

      return {
        type: 'messageEvent',
        message: 'You told your friends you couldn\'t make it. They understood, but you could tell they were disappointed. Maybe next time.',
      };
    }
  }
}

/**
 * Friendship Ending - triggers when affinity drops below -20
 * Try to reconcile (energy -20, 50% chance of recovery) or accept it (clean break, social -3)
 */
export class FriendshipEnding extends BaseEvent {
  readonly id = 'friendshipEnding';

  getConfig(): EventConfig {
    return {
      minAge: 10,
      maxAge: 100,
      baseChance: 0.0005,
      triggerType: 'conditional',
    };
  }

  checkConditions(player: Player): boolean {
    if (player.askedQuestions.has(this.id)) return false;

    return (player.r ?? []).some(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) < -20
    );
  }

  getQuestion(player?: Player): string {
    const friend = (player?.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) < -20
    );
    const name = friend?.firstname ?? 'An old friend';
    return `You and ${name} had a major falling out. The friendship feels beyond repair. What do you do?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Try to reconcile', 'reconcile', 20),
      createAnswerOption('Accept it and move on', 'accept'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const friend = (player.r ?? []).find(
      (p) =>
        p.status === 'alive' &&
        (p.relationships ?? []).includes('friend') &&
        (p.affinity ?? 0) < -20
    );

    if (!friend) {
      return { type: 'messageEvent', message: 'Some friendships just fade away.' };
    }

    const name = friend.firstname;

    if (selectedOption === 0) {
      // Try to reconcile — 50% chance of recovery
      player.c.energy = modifyStat(player.c.energy, -20);

      if (Math.random() < 0.5) {
        // Success!
        friend.affinity = modifyStat(friend.affinity, 30, -100, 100);
        player.c.happiness = modifyStat(player.c.happiness, 10);

        return {
          type: 'messageEvent',
          message: `You reached out to ${name} and had a long, honest conversation. You both acknowledged mistakes and agreed to try again. The friendship isn't what it was, but it has a chance.`,
          energyCost: 20,
          affinityChange: 30,
        };
      } else {
        // Failed
        const idx = (friend.relationships ?? []).indexOf('friend');
        if (idx !== -1) {
          friend.relationships!.splice(idx, 1);
        }
        player.c.happiness = modifyStat(player.c.happiness, -15);
        player.c.social = modifyStat(player.c.social, -3);

        return {
          type: 'messageEvent',
          message: `You tried to reconcile with ${name}, but they weren't interested. "I think we're better off going our separate ways." The friendship is over.`,
          energyCost: 20,
        };
      }
    } else {
      // Accept it — clean break
      const idx = (friend.relationships ?? []).indexOf('friend');
      if (idx !== -1) {
        friend.relationships!.splice(idx, 1);
      }
      // Also remove bestfriend if present
      const bfIdx = (friend.relationships ?? []).indexOf('bestfriend');
      if (bfIdx !== -1) {
        friend.relationships!.splice(bfIdx, 1);
      }
      player.c.happiness = modifyStat(player.c.happiness, -10);
      player.c.social = modifyStat(player.c.social, -3);

      return {
        type: 'messageEvent',
        message: `You accepted that your friendship with ${name} is over. It's painful, but sometimes people grow in different directions. You unfollowed them and moved on.`,
      };
    }
  }
}

// =============================================================================
// Exports
// =============================================================================

// Event class instances for fast mode events
export const bestFriendMilestoneInstance = new BestFriendMilestone();
export const friendBetrayalInstance = new FriendBetrayal();
export const friendInCrisisInstance = new FriendInCrisis();
export const groupTripInstance = new GroupTrip();
export const friendshipEndingInstance = new FriendshipEnding();

// All class-based friendship events (added to classBasedEvents)
export const friendshipClassEvents = [
  bestFriendMilestoneInstance,
  friendBetrayalInstance,
  friendInCrisisInstance,
  groupTripInstance,
  friendshipEndingInstance,
];

// Function-based friendship events (added to allEvents)
export const friendshipEvents = {
  friendCoffeeInvite,
  friendHelpMoving,
  friendToughTime,
  friendBirthday,
  friendGossipChoice,
  friendDecayWarning,
  friendConcertInvite,
  friendLendMoney,
};
