/**
 * Social Events
 * Ported from Python ws/events/activities/social.py
 *
 * Events:
 * - communityEvent: Attend or help organize community events (ages 8-100)
 * - gamingGroup: Join regular gaming nights (ages 10-100)
 * - joinClub: Join a club for one of your interests (ages 12-100)
 * - volunteerWork: Volunteer for a local organization (ages 14-100)
 *
 * All events follow the BaseEvent pattern and include:
 * - Age restrictions
 * - Schedule entries for recurring activities
 * - Social stat effects and relationship building
 */

import { v4 as uuidv4 } from 'uuid';
import {
  BaseEvent,
  EventResult,
  AnswerOption,
  EventConfig,
  createAnswerOption,
} from '../base.js';
import type { Player } from '../../models/Player.js';
import type { Person, Schedule } from '../../models/Person.js';
import type { ActivityRecordData } from '../../models/ActivityRecord.js';

// =============================================================================
// Types
// =============================================================================

export type FocusType = 'Work Hard' | 'Balanced' | 'Slack Off' | 'Socialize';

interface SocialActivityData {
  id: string;
  title: string;
  type: string;
  description: string;
  energyModifier: number;
}

// =============================================================================
// Helper Functions
// =============================================================================

/**
 * Check if a person already has an activity with a given title
 */
function hasActivity(person: Person, activityTitle: string): boolean {
  return person.activities?.some((a) => a.title === activityTitle) ?? false;
}

/**
 * Add a social activity to a person with tracking
 */
function addSocialActivity(
  person: Person,
  activityTitle: string,
  focus: FocusType,
  description: string,
  date: string,
  performanceTracking: boolean = false
): { activity: SocialActivityData; record: ActivityRecordData } {
  const activityId = uuidv4();

  const activity: SocialActivityData = {
    id: activityId,
    title: activityTitle,
    type: 'social',
    description,
    energyModifier: 15,
  };

  // Add to activities array
  person.activities = person.activities ?? [];
  person.activities.push(activity);

  // Create activity record for tracking
  const record: ActivityRecordData = {
    id: activityId,
    type: 'social',
    dateStarted: date,
    performance: performanceTracking ? 0 : 50,
    focus,
    achievements: [],
  };

  person.activityRecords = person.activityRecords ?? [];
  person.activityRecords.push(record);

  return { activity, record };
}

/**
 * Create a schedule for an activity
 */
function createActivitySchedule(
  person: Person,
  title: string,
  frequency: string[],
  location: string,
  durationWeeks: number
): Schedule {
  const schedule: Schedule = {
    id: `${title.toLowerCase().replace(/\s+/g, '-')}-${person.id}`,
    title,
    location,
    duration: durationWeeks,
    executions: 0,
    type: 'activity',
    days: {
      daysOfWeek: frequency.includes('weekend')
        ? ['6', '7']
        : frequency.includes('weekday')
        ? ['1', '2', '3', '4', '5']
        : ['1', '2', '3', '4', '5', '6', '7'],
      hour: frequency.includes('morning')
        ? 9
        : frequency.includes('afternoon')
        ? 14
        : frequency.includes('evening')
        ? 18
        : 12,
    },
  };

  person.schedules = person.schedules ?? [];
  person.schedules.push(schedule);

  return schedule;
}

/**
 * Build relationships with people who share a social activity
 */
function buildRelationshipsAtActivity(
  player: Player,
  activityName: string,
  affinityBoost: number = 5
): number {
  let relationshipsBuilt = 0;

  for (const relPerson of player.r ?? []) {
    if (hasActivity(relPerson, activityName)) {
      relPerson.affinity = Math.min(100, (relPerson.affinity ?? 50) + affinityBoost);
      relationshipsBuilt++;
    }
  }

  return relationshipsBuilt;
}

/**
 * Ensure community location exists for a player
 */
function ensureCommunityLocation(player: Player): string {
  const communityId = `community-${player.c.id}`;

  player.l = player.l ?? [];
  if (!player.l.some((loc) => loc.id === communityId)) {
    player.l.push({
      id: communityId,
      type: 'community',
    });
  }

  return communityId;
}

/**
 * Ensure friend location exists for a player
 */
function ensureFriendLocation(player: Player): string {
  const friendId = `friend-${player.c.id}`;

  player.l = player.l ?? [];
  if (!player.l.some((loc) => loc.id === friendId)) {
    player.l.push({
      id: friendId,
      type: 'friend',
    });
  }

  return friendId;
}

// =============================================================================
// Community Event (ages 8-100)
// =============================================================================

const COMMUNITY_EVENT_TYPES = [
  'Neighborhood Block Party',
  'Community Festival',
  'Farmers Market',
  'Charity Fundraiser',
  'Local Art Fair',
  'Music in the Park',
  'Community Cleanup Day',
  'Holiday Celebration',
  'Sports Tournament',
  'Cultural Festival',
];

/**
 * Community Event - Attend or help organize community events
 */
export class CommunityEvent extends BaseEvent {
  readonly id = 'communityEvent';

  private eventName: string = '';

  private getRandomEventType(): string {
    return COMMUNITY_EVENT_TYPES[Math.floor(Math.random() * COMMUNITY_EVENT_TYPES.length)];
  }

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

  checkConditions(player: Player): boolean {
    const c = player.c;
    return (
      !player.askedQuestions.has(this.id) &&
      c.ageYears >= 8 &&
      c.ageYears <= 100
    );
  }

  getQuestion(player?: Player): string {
    this.eventName = this.getRandomEventType();
    return `There's a ${this.eventName} this weekend. Attend?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Yes, participate actively!', 'participate', 15),
      createAnswerOption('Just attend casually', 'attend'),
      createAnswerOption('Help organize it!', 'organize', 30, 10),
      createAnswerOption('Skip it', 'no'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const c = player.c;
    const eventName = this.eventName || this.getRandomEventType();

    if (selectedOption === 0) {
      // Participate actively
      c.social = Math.min(100, (c.social ?? 50) + 20);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 15);
      c.energy = Math.max(0, (c.energy ?? 100) - 15);

      // Build relationships with community members
      const numPeopleMet = Math.min(3, (player.r ?? []).length);
      if (numPeopleMet > 0) {
        const shuffled = [...(player.r ?? [])].sort(() => 0.5 - Math.random());
        const metPeople = shuffled.slice(0, numPeopleMet);
        for (const person of metPeople) {
          person.affinity = Math.min(100, (person.affinity ?? 50) + Math.floor(Math.random() * 6) + 3);
          person.familiarity = (person.familiarity ?? 0) + Math.floor(Math.random() * 6) + 5;
        }
      }

      let message = `You actively participated in the ${eventName} and had a great time!`;
      if (numPeopleMet > 0) {
        message += ` You met and bonded with ${numPeopleMet} people at the event!`;
      }

      return {
        type: 'messageEvent',
        message,
        energyCost: 15,
      };
    } else if (selectedOption === 1) {
      // Attend casually
      c.social = Math.min(100, (c.social ?? 50) + 10);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 10);

      // Lower chance of meeting people
      const numPeopleMet = Math.floor(Math.random() * Math.min(3, (player.r ?? []).length));
      if (numPeopleMet > 0) {
        const shuffled = [...(player.r ?? [])].sort(() => 0.5 - Math.random());
        const metPeople = shuffled.slice(0, numPeopleMet);
        for (const person of metPeople) {
          person.affinity = Math.min(100, (person.affinity ?? 50) + Math.floor(Math.random() * 5) + 1);
          person.familiarity = (person.familiarity ?? 0) + Math.floor(Math.random() * 5) + 3;
        }
      }

      let message = `You casually attended the ${eventName}.`;
      if (numPeopleMet > 0) {
        message += ` You ran into ${numPeopleMet} familiar face(s) at the event!`;
      }

      return {
        type: 'messageEvent',
        message,
      };
    } else if (selectedOption === 2) {
      // Help organize
      c.social = Math.min(100, (c.social ?? 50) + 30);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
      c.energy = Math.max(0, (c.energy ?? 100) - 30);
      c.prestige = (c.prestige ?? 0) + 8;

      // Higher chance of meeting and bonding with more people
      const numPeopleMet = Math.min(5, (player.r ?? []).length);
      if (numPeopleMet > 0) {
        const shuffled = [...(player.r ?? [])].sort(() => 0.5 - Math.random());
        const metPeople = shuffled.slice(0, numPeopleMet);
        for (const person of metPeople) {
          person.affinity = Math.min(100, (person.affinity ?? 50) + Math.floor(Math.random() * 8) + 5);
          person.familiarity = (person.familiarity ?? 0) + Math.floor(Math.random() * 8) + 8;
        }
      }

      // Small chance for bonus reward
      if (Math.random() < 0.3) {
        c.diamonds = (c.diamonds ?? 0) + 5;
        let message = `You helped organize the ${eventName}! Everyone appreciated your hard work. The community recognized your leadership and gave you a small reward!`;
        if (numPeopleMet > 0) {
          message += ` You connected with ${numPeopleMet} community member(s)!`;
        }
        return {
          type: 'messageEvent',
          message,
          energyCost: 30,
          diamondCost: -5, // Reward
        };
      }

      let message = `You helped organize the ${eventName}! Everyone appreciated your hard work.`;
      if (numPeopleMet > 0) {
        message += ` You connected with ${numPeopleMet} community member(s)!`;
      }

      return {
        type: 'messageEvent',
        message,
        energyCost: 30,
      };
    } else {
      // Skip it
      c.happiness = Math.max(0, (c.happiness ?? 50) - 5);
      return {
        type: 'messageEvent',
        message: `You decided to skip the ${eventName}.`,
      };
    }
  }
}

// =============================================================================
// Gaming Group (ages 10-100)
// =============================================================================

const GAMING_TYPES = [
  { name: 'Board Game Night', description: 'Play board games with friends' },
  { name: 'Video Game Night', description: 'Team up for multiplayer gaming' },
  { name: 'Tabletop RPG Group', description: 'Create epic adventures together' },
  { name: 'Card Game Night', description: 'Master strategy card games' },
  { name: 'Retro Gaming Club', description: 'Relive classic video games' },
  { name: 'Party Game Night', description: 'Fun social party games' },
];

/**
 * Gaming Group - Join regular gaming nights
 */
export class GamingGroup extends BaseEvent {
  readonly id = 'gamingGroup';

  private gamingType: { name: string; description: string } | null = null;

  private getRandomGamingType(): { name: string; description: string } {
    return GAMING_TYPES[Math.floor(Math.random() * GAMING_TYPES.length)];
  }

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

  checkConditions(player: Player): boolean {
    const c = player.c;
    const gamingType = this.getRandomGamingType();

    return (
      !player.askedQuestions.has(this.id) &&
      c.ageYears >= 10 &&
      c.ageYears <= 100 &&
      !hasActivity(c, gamingType.name)
    );
  }

  getQuestion(player?: Player): string {
    this.gamingType = this.getRandomGamingType();
    return `Friends invite you to a regular ${this.gamingType.name}. Join?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Yes, weekly gaming!', 'weekly'),
      createAnswerOption('Join occasionally', 'occasional'),
      createAnswerOption('Not my thing', 'no'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const c = player.c;
    const gamingType = this.gamingType || this.getRandomGamingType();

    if (selectedOption === 0) {
      // Weekly gaming - add activity with tracking and schedule
      addSocialActivity(
        c,
        gamingType.name,
        'Socialize',
        gamingType.description,
        player.date,
        true
      );

      // Create friend location if it doesn't exist
      const friendId = ensureFriendLocation(player);

      // Create gaming night schedule (weekly for 16-24 weeks)
      const durationWeeks = Math.floor(Math.random() * 9) + 16;
      createActivitySchedule(
        c,
        gamingType.name,
        ['weekly', 'evening', 'weekend'],
        friendId,
        durationWeeks
      );

      // Stat bonuses
      c.social = Math.min(100, (c.social ?? 50) + 25);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
      c.stress = Math.max(0, (c.stress ?? 0) - 10);

      // Build relationships with gaming buddies
      const relationshipsCount = buildRelationshipsAtActivity(player, gamingType.name, 6);

      let message = `You joined ${gamingType.name}! See you at the next session. The group will meet weekly for ${durationWeeks} weeks. Have fun!`;
      if (relationshipsCount > 0) {
        message += ` You're bonding with ${relationshipsCount} gaming friend(s)!`;
      }

      return {
        type: 'messageEvent',
        message,
      };
    } else if (selectedOption === 1) {
      // Occasional
      c.social = Math.min(100, (c.social ?? 50) + 15);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 15);
      c.stress = Math.max(0, (c.stress ?? 0) - 5);

      return {
        type: 'messageEvent',
        message: `You'll join ${gamingType.name} when you can make it!`,
      };
    } else {
      // Decline
      c.social = Math.max(0, (c.social ?? 50) - 10);
      return {
        type: 'messageEvent',
        message: "You decided gaming nights aren't for you.",
      };
    }
  }
}

// =============================================================================
// Join Club (ages 12-100)
// =============================================================================

const CLUB_TYPES = [
  { name: 'Photography Club', description: 'Share your passion for photography' },
  { name: 'Hiking Club', description: 'Explore nature trails with others' },
  { name: 'Cooking Club', description: 'Learn new recipes together' },
  { name: 'Art Club', description: 'Express creativity through art' },
  { name: 'Music Club', description: 'Share your love of music' },
  { name: 'Film Club', description: 'Watch and discuss movies' },
  { name: 'Tech Club', description: 'Learn about technology together' },
  { name: 'Gardening Club', description: 'Grow plants and share gardening tips' },
];

/**
 * Join Club - Join a club for one of your interests
 */
export class JoinClub extends BaseEvent {
  readonly id = 'joinClub';

  private clubType: { name: string; description: string } | null = null;

  private getRandomClubType(): { name: string; description: string } {
    return CLUB_TYPES[Math.floor(Math.random() * CLUB_TYPES.length)];
  }

  getConfig(): EventConfig {
    return {
      minAge: 12,
      maxAge: 100,
      baseChance: 0.001,
      triggerType: 'random',
    };
  }

  checkConditions(player: Player): boolean {
    const c = player.c;
    const clubType = this.getRandomClubType();

    return (
      !player.askedQuestions.has(this.id) &&
      c.ageYears >= 12 &&
      c.ageYears <= 100 &&
      !hasActivity(c, clubType.name)
    );
  }

  getQuestion(player?: Player): string {
    this.clubType = this.getRandomClubType();
    return `There's a ${this.clubType.name} in your area. Join?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Yes, become a member!', 'join'),
      createAnswerOption('Attend as guest first', 'guest'),
      createAnswerOption('Not interested', 'no'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const c = player.c;
    const clubType = this.clubType || this.getRandomClubType();

    if (selectedOption === 0) {
      // Join the club - add activity with tracking and schedule
      addSocialActivity(
        c,
        clubType.name,
        'Socialize',
        clubType.description,
        player.date,
        true
      );

      // Create community location if it doesn't exist
      const communityId = ensureCommunityLocation(player);

      // Create recurring club meeting schedule (8-12 weeks)
      const durationWeeks = Math.floor(Math.random() * 5) + 8;
      createActivitySchedule(
        c,
        clubType.name,
        ['weekly', 'evening'],
        communityId,
        durationWeeks
      );

      // Stat bonuses
      c.social = Math.min(100, (c.social ?? 50) + 25);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 15);

      // Build relationships with others in similar activities
      const relationshipsCount = buildRelationshipsAtActivity(player, clubType.name, 3);

      let message = `You joined ${clubType.name}! Meetings are weekly for ${durationWeeks} weeks.`;
      if (relationshipsCount > 0) {
        message += ` You're getting closer to ${relationshipsCount} club member(s)!`;
      }

      return {
        type: 'messageEvent',
        message,
      };
    } else if (selectedOption === 1) {
      // Attend as guest
      c.social = Math.min(100, (c.social ?? 50) + 10);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 10);

      return {
        type: 'messageEvent',
        message: `You attended ${clubType.name} as a guest and enjoyed it!`,
      };
    } else {
      // Decline
      c.happiness = Math.max(0, (c.happiness ?? 50) - 5);
      return {
        type: 'messageEvent',
        message: 'You decided not to join the club.',
      };
    }
  }
}

// =============================================================================
// Volunteer Work (ages 14-100)
// =============================================================================

const VOLUNTEER_TYPES = [
  { name: 'Animal Shelter', description: 'Help care for animals in need' },
  { name: 'Food Bank', description: 'Sort and distribute food to those in need' },
  { name: 'Elderly Care', description: 'Visit and assist elderly community members' },
  { name: 'Environmental Cleanup', description: 'Help clean parks and public spaces' },
  { name: 'Youth Mentoring', description: 'Guide and inspire young people' },
  { name: 'Homeless Outreach', description: 'Provide support to homeless individuals' },
  { name: 'Library Assistance', description: 'Help organize and run library programs' },
];

/**
 * Volunteer Work - Volunteer for a local organization
 */
export class VolunteerWork extends BaseEvent {
  readonly id = 'volunteerWork';

  private volunteerType: { name: string; description: string } | null = null;

  private getRandomVolunteerType(): { name: string; description: string } {
    return VOLUNTEER_TYPES[Math.floor(Math.random() * VOLUNTEER_TYPES.length)];
  }

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

  checkConditions(player: Player): boolean {
    const c = player.c;
    const volunteerType = this.getRandomVolunteerType();
    const activityTitle = `${volunteerType.name} Volunteer`;

    return (
      !player.askedQuestions.has(this.id) &&
      c.ageYears >= 14 &&
      c.ageYears <= 100 &&
      !hasActivity(c, activityTitle)
    );
  }

  getQuestion(player?: Player): string {
    this.volunteerType = this.getRandomVolunteerType();
    return `A local ${this.volunteerType.name} needs volunteers. Help out?`;
  }

  getAnswerOptions(): AnswerOption[] {
    return [
      createAnswerOption('Yes, volunteer regularly!', 'regular'),
      createAnswerOption('Volunteer occasionally', 'occasional'),
      createAnswerOption('Donate money instead', 'donate', 0, 0, 50),
      createAnswerOption('Not right now', 'no'),
    ];
  }

  processAnswer(player: Player, selectedOption: number): EventResult {
    const c = player.c;
    const volunteerType = this.volunteerType || this.getRandomVolunteerType();
    const activityTitle = `${volunteerType.name} Volunteer`;

    if (selectedOption === 0) {
      // Regular volunteering - add activity with performance tracking
      addSocialActivity(
        c,
        activityTitle,
        'Balanced',
        volunteerType.description,
        player.date,
        true // Track volunteer hours
      );

      // Create community location if it doesn't exist
      const communityId = ensureCommunityLocation(player);

      // Create volunteer schedule (12-24 weeks, weekend mornings)
      const durationWeeks = Math.floor(Math.random() * 13) + 12;
      createActivitySchedule(
        c,
        activityTitle,
        ['weekly', 'weekend', 'morning'],
        communityId,
        durationWeeks
      );

      // Stat bonuses
      c.social = Math.min(100, (c.social ?? 50) + 20);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
      c.prestige = (c.prestige ?? 0) + 5;

      // Build relationships with other volunteers
      const relationshipsCount = buildRelationshipsAtActivity(player, activityTitle, 4);

      let message = `You signed up to volunteer at ${volunteerType.name} regularly! You'll volunteer for ${durationWeeks} weeks. Your work helps the community.`;
      if (relationshipsCount > 0) {
        message += ` You bonded with ${relationshipsCount} fellow volunteer(s)!`;
      }

      return {
        type: 'messageEvent',
        message,
      };
    } else if (selectedOption === 1) {
      // Occasional volunteering
      c.social = Math.min(100, (c.social ?? 50) + 15);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
      c.prestige = (c.prestige ?? 0) + 2;

      return {
        type: 'messageEvent',
        message: `You'll volunteer at ${volunteerType.name} when you have time. Every bit helps!`,
      };
    } else if (selectedOption === 2) {
      // Donate money
      if ((c.money ?? 0) < 50) {
        return {
          type: 'messageEvent',
          message: "You don't have enough money to donate right now.",
        };
      }
      c.money = (c.money ?? 0) - 50;
      c.happiness = Math.min(100, (c.happiness ?? 50) + 15);
      c.prestige = (c.prestige ?? 0) + 3;

      return {
        type: 'messageEvent',
        message: `You made a $50 donation to ${volunteerType.name} to support the cause!`,
        moneyCost: 50,
      };
    } else {
      // Decline
      c.happiness = Math.max(0, (c.happiness ?? 50) - 10);
      return {
        type: 'messageEvent',
        message: 'You decided not to volunteer right now.',
      };
    }
  }
}

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

// Event class instances
export const communityEventInstance = new CommunityEvent();
export const gamingGroupInstance = new GamingGroup();
export const joinClubInstance = new JoinClub();
export const volunteerWorkInstance = new VolunteerWork();

// All social events combined
export const socialEvents = [
  communityEventInstance,
  gamingGroupInstance,
  joinClubInstance,
  volunteerWorkInstance,
];

// Export helper functions for reuse
export {
  hasActivity,
  addSocialActivity,
  createActivitySchedule,
  buildRelationshipsAtActivity,
  ensureCommunityLocation,
  ensureFriendLocation,
};
