/**
 * Activity Learning Progress System
 * Ported from Python ws/events/activities/learning.py, physical.py, social.py
 *
 * This module provides:
 * 1. Progress tracking events for learning activities (online courses, languages, bootcamps, music, cooking)
 * 2. Progress tracking events for physical activities (soccer, martial arts, running, gym, yoga)
 * 3. Helper functions for activity management
 * 4. Game loop integration for continuous progress updates
 */

import { v4 as uuidv4 } from 'uuid';
import type { Player } from '../../models/Player.js';
import type { Person, Schedule } from '../../models/Person.js';
import {
  ActivityRecord,
  type ActivityRecordData,
  getActivityRecord,
  hasActivity as hasActivityRecord,
} from '../../models/ActivityRecord.js';
import { OneTimeEvent, type OneTimeEventData } from '../../models/OneTimeEvent.js';
import {
  type FocusType,
  FOCUS_PERFORMANCE_MULTIPLIERS,
  LEARNING_FOCUS_MAP as IMPORTED_LEARNING_FOCUS_MAP,
  PHYSICAL_FOCUS_MAP as IMPORTED_PHYSICAL_FOCUS_MAP,
} from '../../constants/focus.js';

// Re-export FocusType for consumers
export type { FocusType };

export interface ProgressResult {
  message: string;
  statChanges?: {
    intelligence?: number;
    happiness?: number;
    social?: number;
    stress?: number;
    prestige?: number;
    health?: number;
    money?: number;
    energy?: number;
  };
  achievement?: string;
  completed?: boolean;
  scheduleNextCheck?: {
    daysFromNow: number;
    title: string;
    message: string;
  };
}

// Focus modifiers imported from centralized constants
const FOCUS_MODIFIERS = FOCUS_PERFORMANCE_MULTIPLIERS;
const LEARNING_FOCUS_MAP = IMPORTED_LEARNING_FOCUS_MAP;
const PHYSICAL_FOCUS_MAP = IMPORTED_PHYSICAL_FOCUS_MAP;

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

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

/**
 * Get an activity record by ID from a person
 */
export function getActivityRecordById(
  person: Person,
  activityId: string
): ActivityRecordData | undefined {
  return person.activityRecords?.find((r) => r.id === activityId);
}

/**
 * Get an activity record by type from a person
 */
export function getActivityRecordByType(
  person: Person,
  activityType: string
): ActivityRecordData | undefined {
  return person.activityRecords?.find((r) => r.type === activityType);
}

/**
 * Increment activity performance for a specific record
 */
export function incrementActivityPerformance(
  person: Person,
  activityId: string,
  amount: number = 1
): void {
  const record = person.activityRecords?.find((r) => r.id === activityId);
  if (record) {
    record.performance = Math.min(100, (record.performance ?? 0) + amount);
  }
}

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

  const activity = {
    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 };
}

/**
 * Build relationships with people who share an activity
 * Boosts affinity with relationship characters who have the same activity
 */
export 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;
}

/**
 * Schedule a one-time progress check event
 */
export function scheduleProgressCheck(
  person: Person,
  title: string,
  message: string,
  daysFromNow: number,
  completionFunc: string,
  completionArgs: Record<string, unknown> = {}
): void {
  const event: OneTimeEventData = {
    id: uuidv4(),
    title,
    message,
    dateType: 'daysFromNow',
    dateModifier: daysFromNow,
    hour: 12,
    completionFunc,
    completionArgs: [completionArgs],
  };

  person.oneTimeEvents = person.oneTimeEvents ?? [];
  person.oneTimeEvents.push(event as any);
}

/**
 * Create an activity record for a learning activity
 */
export function createLearningActivityRecord(
  person: Person,
  id: string,
  type: string,
  topic: string,
  startingPerformance: number = 0,
  focus: FocusType = 'Balanced'
): ActivityRecordData {
  const record: ActivityRecordData = {
    id,
    type,
    dateStarted: new Date().toISOString().split('T')[0],
    performance: startingPerformance,
    focus,
    achievements: [],
    level: topic as any, // Store topic in level field for convenience
  };

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

  return record;
}

/**
 * Create a schedule for an activity
 */
export function createActivitySchedule(
  person: Person,
  title: string,
  frequency: string[],
  location: string,
  duration: number
): Schedule {
  const schedule: Schedule = {
    id: `${title.toLowerCase().replace(/\s+/g, '-')}-${person.id}`,
    title,
    location,
    duration,
    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;
}

// =============================================================================
// Learning Activity Progress Functions
// =============================================================================

/**
 * Process online course progress
 */
export function onlineCourseProgress(
  player: Player,
  courseRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === courseRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = LEARNING_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const topic = record.level ?? 'the subject';

  if (record.performance >= 100) {
    // Course completed!
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 20);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
    record.achievements = record.achievements ?? [];
    record.achievements.push(`Completed ${topic}`);

    // If job-related, boost job performance
    if (c.job) {
      const jobRecord = c.activityRecords?.find((r) => r.type === 'job');
      if (jobRecord) {
        jobRecord.performance = Math.min(100, (jobRecord.performance ?? 50) + 15);
      }
    }

    return {
      message: `Congratulations! You've completed your ${topic} course with a strong understanding of the material. This new knowledge will serve you well!`,
      statChanges: { intelligence: 20, happiness: 25 },
      achievement: `Completed ${topic}`,
      completed: true,
    };
  } else if (record.performance >= 75) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 10);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 10);

    return {
      message: `You're making excellent progress in your ${topic} course! You're really grasping the concepts.`,
      statChanges: { intelligence: 10, happiness: 10 },
      scheduleNextCheck: {
        daysFromNow: 21,
        title: 'Online Course Final Check',
        message: `Final stretch of your ${topic} course!`,
      },
    };
  } else if (record.performance >= 50) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 5);

    return {
      message: `You're making steady progress in your ${topic} course. Keep at it!`,
      statChanges: { intelligence: 5 },
      scheduleNextCheck: {
        daysFromNow: 21,
        title: 'Online Course Progress Check',
        message: `Continuing your ${topic} course`,
      },
    };
  } else {
    c.happiness = Math.max(0, (c.happiness ?? 50) - 10);
    c.stress = Math.min(100, (c.stress ?? 0) + 10);

    return {
      message: `You're struggling to keep up with your ${topic} course. You might need to put in more effort or consider dropping it.`,
      statChanges: { happiness: -10, stress: 10 },
    };
  }
}

/**
 * Process language learning progress
 */
export function languageLearningProgress(
  player: Player,
  languageRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === languageRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  let progressGain = LEARNING_FOCUS_MAP[focus];

  // Socialize focus helps with language learning
  if (focus === 'Socialize') {
    progressGain = 12; // Bonus for social focus
  }

  // App-based learning is slower
  if (record.type === 'language_learning_app') {
    progressGain = Math.floor(progressGain * 0.6);
  }

  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const language = record.level ?? 'the language';
  const achievements = record.achievements ?? [];

  // Proficiency levels: 0-24 Beginner, 25-49 Elementary, 50-74 Intermediate, 75-89 Advanced, 90-100 Fluent

  if (record.performance >= 90 && !achievements.includes(`Fluent in ${language}`)) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 30);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 35);
    record.achievements = [...achievements, `Fluent in ${language}`];

    // Job benefits for language-related jobs
    if (c.job?.title) {
      const jobTitle = c.job.title;
      if (['Teacher', 'Translator', 'Diplomat', 'International'].some((w) => jobTitle.includes(w))) {
        const jobRecord = c.activityRecords?.find((r) => r.type === 'job');
        if (jobRecord) {
          jobRecord.performance = Math.min(100, (jobRecord.performance ?? 50) + 20);
        }
      }
    }

    return {
      message: `Amazing! You've achieved fluency in ${language}! You can now comfortably speak, read, and write in the language. This is a major accomplishment!`,
      statChanges: { intelligence: 30, happiness: 35 },
      achievement: `Fluent in ${language}`,
      completed: true,
    };
  } else if (record.performance >= 75 && !achievements.includes(`Advanced ${language}`)) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 20);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    record.achievements = [...achievements, `Advanced ${language}`];

    return {
      message: `You've reached an advanced level in ${language}! You can hold complex conversations and understand most native content.`,
      statChanges: { intelligence: 20, happiness: 20 },
      achievement: `Advanced ${language}`,
      scheduleNextCheck: {
        daysFromNow: 84,
        title: `${language} Learning Progress`,
        message: `Approaching fluency in ${language}!`,
      },
    };
  } else if (record.performance >= 50 && !achievements.includes(`Intermediate ${language}`)) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 15);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 15);
    record.achievements = [...achievements, `Intermediate ${language}`];

    return {
      message: `You've reached an intermediate level in ${language}! You can handle everyday conversations with growing confidence.`,
      statChanges: { intelligence: 15, happiness: 15 },
      achievement: `Intermediate ${language}`,
      scheduleNextCheck: {
        daysFromNow: 84,
        title: `${language} Learning Progress`,
        message: `Continuing ${language} studies`,
      },
    };
  } else if (record.performance >= 25 && !achievements.includes(`Elementary ${language}`)) {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 10);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 10);
    record.achievements = [...achievements, `Elementary ${language}`];

    return {
      message: `You've reached an elementary level in ${language}! You can introduce yourself and handle basic conversations.`,
      statChanges: { intelligence: 10, happiness: 10 },
      achievement: `Elementary ${language}`,
      scheduleNextCheck: {
        daysFromNow: 84,
        title: `${language} Learning Progress`,
        message: `Progressing in ${language}`,
      },
    };
  } else {
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 5);

    if (focus === 'Slack Off') {
      c.happiness = Math.max(0, (c.happiness ?? 50) - 5);
      return {
        message: `Your ${language} progress is slow. You might need to dedicate more time to studying if you want to improve.`,
        statChanges: { intelligence: 5, happiness: -5 },
        scheduleNextCheck: {
          daysFromNow: 56,
          title: `${language} Learning Progress`,
          message: `Building skills in ${language}`,
        },
      };
    }

    return {
      message: `You're building a foundation in ${language}. The beginning is always the hardest part!`,
      statChanges: { intelligence: 5 },
      scheduleNextCheck: {
        daysFromNow: 56,
        title: `${language} Learning Progress`,
        message: `Building skills in ${language}`,
      },
    };
  }
}

/**
 * Process coding bootcamp progress
 */
export function codingBootcampProgress(
  player: Player,
  bootcampRecordId: string,
  stage: 'midpoint' | 'completion' = 'midpoint'
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === bootcampRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const focusMap: Record<FocusType, number> = {
    'Work Hard': 30,
    'Balanced': 20,
    'Slack Off': 5,
    'Socialize': 15,
  };

  let progressGain = focusMap[focus];

  // Part-time bootcamp progresses slower
  if (record.type === 'coding_bootcamp_parttime') {
    progressGain = Math.floor(progressGain * 0.7);
  }

  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const specialization = record.level ?? 'programming';
  const achievements = record.achievements ?? [];

  if (stage === 'midpoint') {
    if (record.performance >= 70) {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 15);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 15);
      record.achievements = [...achievements, `Excellent Progress - ${specialization}`];

      const completionDays = record.type === 'coding_bootcamp' ? 42 : 70;

      return {
        message: `You're excelling in the ${specialization} bootcamp! Your instructors are impressed with your progress.`,
        statChanges: { intelligence: 15, happiness: 15 },
        scheduleNextCheck: {
          daysFromNow: completionDays,
          title: 'Bootcamp Graduation',
          message: `Final days of ${specialization} bootcamp!`,
        },
      };
    } else if (record.performance >= 50) {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 10);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 10);

      const completionDays = record.type === 'coding_bootcamp' ? 42 : 70;

      return {
        message: `You're making solid progress in the ${specialization} bootcamp. Keep pushing through!`,
        statChanges: { intelligence: 10, happiness: 10 },
        scheduleNextCheck: {
          daysFromNow: completionDays,
          title: 'Bootcamp Graduation',
          message: `Final days of ${specialization} bootcamp!`,
        },
      };
    } else {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 5);
      c.happiness = Math.max(0, (c.happiness ?? 50) - 10);
      c.stress = Math.min(100, (c.stress ?? 0) + 15);

      const completionDays = record.type === 'coding_bootcamp' ? 42 : 70;

      return {
        message: `You're struggling to keep up in the ${specialization} bootcamp. The pace is intense and you're feeling overwhelmed.`,
        statChanges: { intelligence: 5, happiness: -10, stress: 15 },
        scheduleNextCheck: {
          daysFromNow: completionDays,
          title: 'Bootcamp Graduation',
          message: `Final days of ${specialization} bootcamp!`,
        },
      };
    }
  } else {
    // Completion stage
    // Remove bootcamp schedule
    c.schedules = c.schedules?.filter((s) => !s.title?.includes(specialization)) ?? [];

    if (record.performance >= 80) {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 40);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 40);
      c.prestige = (c.prestige ?? 0) + 15;
      record.achievements = [...achievements, `Graduated with Honors - ${specialization}`];

      return {
        message: `Congratulations! You graduated from the ${specialization} bootcamp with honors! You now have the skills to pursue careers in ${specialization}.`,
        statChanges: { intelligence: 40, happiness: 40, prestige: 15 },
        achievement: `Graduated with Honors - ${specialization}`,
        completed: true,
      };
    } else if (record.performance >= 60) {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 30);
      c.happiness = Math.min(100, (c.happiness ?? 50) + 30);
      c.prestige = (c.prestige ?? 0) + 10;
      record.achievements = [...achievements, `Completed ${specialization}`];

      return {
        message: `You graduated from the ${specialization} bootcamp! You have a solid foundation in programming and are ready to start your career transition.`,
        statChanges: { intelligence: 30, happiness: 30, prestige: 10 },
        achievement: `Completed ${specialization}`,
        completed: true,
      };
    } else {
      c.intelligence = Math.min(100, (c.intelligence ?? 50) + 15);
      c.happiness = Math.max(0, (c.happiness ?? 50) - 20);
      c.stress = Math.min(100, (c.stress ?? 0) + 20);
      record.achievements = [...achievements, `Completed ${specialization} (with difficulty)`];

      return {
        message: `You completed the ${specialization} bootcamp, but it was a real struggle. You learned some things, but feel you need more practice before feeling job-ready.`,
        statChanges: { intelligence: 15, happiness: -20, stress: 20 },
        achievement: `Completed ${specialization} (with difficulty)`,
        completed: true,
      };
    }
  }
}

/**
 * Process music lessons progress
 */
export function musicLessonsProgress(
  player: Player,
  musicRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === musicRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const focusMap: Record<FocusType, number> = {
    'Work Hard': 12,
    'Balanced': 8,
    'Slack Off': 2,
    'Socialize': 6,
  };

  let progressGain = focusMap[focus];

  // Self-taught progresses slower
  if (record.type === 'music_self_taught') {
    progressGain = Math.floor(progressGain * 0.5);
  }

  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const instrument = record.level ?? 'the instrument';
  const achievements = record.achievements ?? [];

  // Skill levels: 0-19 Beginner, 20-49 Amateur, 50-74 Skilled, 75-89 Expert, 90-100 Master

  if (record.performance >= 90 && !achievements.includes(`Master ${instrument} Player`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 50);
    c.prestige = (c.prestige ?? 0) + 20;
    c.stress = Math.max(0, (c.stress ?? 0) - 20);
    record.achievements = [...achievements, `Master ${instrument} Player`];

    // Could potentially earn money performing
    let bonusMessage = '';
    if (Math.random() < 0.3) {
      const earnings = Math.floor(Math.random() * 301) + 200;
      c.money = (c.money ?? 0) + earnings;
      bonusMessage = ` Your skill has opened up performance opportunities! You earned $${earnings} from a recent gig.`;
    }

    return {
      message: `You've achieved mastery of the ${instrument}! You can play complex pieces with emotion and technical perfection. People are moved when they hear you play.${bonusMessage}`,
      statChanges: { happiness: 50, prestige: 20, stress: -20 },
      achievement: `Master ${instrument} Player`,
      completed: true,
    };
  } else if (record.performance >= 75 && !achievements.includes(`Expert ${instrument} Player`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 30);
    c.prestige = (c.prestige ?? 0) + 10;
    c.stress = Math.max(0, (c.stress ?? 0) - 15);
    record.achievements = [...achievements, `Expert ${instrument} Player`];

    return {
      message: `You've become an expert ${instrument} player! You can tackle difficult pieces and your playing sounds professional.`,
      statChanges: { happiness: 30, prestige: 10, stress: -15 },
      achievement: `Expert ${instrument} Player`,
      scheduleNextCheck: {
        daysFromNow: 120,
        title: `${instrument} Progress`,
        message: `Advancing toward mastery of ${instrument}`,
      },
    };
  } else if (record.performance >= 50 && !achievements.includes(`Skilled ${instrument} Player`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
    c.stress = Math.max(0, (c.stress ?? 0) - 10);
    record.achievements = [...achievements, `Skilled ${instrument} Player`];

    return {
      message: `You've become a skilled ${instrument} player! You can play intermediate pieces confidently and your playing brings you joy.`,
      statChanges: { happiness: 25, stress: -10 },
      achievement: `Skilled ${instrument} Player`,
      scheduleNextCheck: {
        daysFromNow: 120,
        title: `${instrument} Progress`,
        message: `Continuing ${instrument} practice`,
      },
    };
  } else if (record.performance >= 20 && !achievements.includes(`Amateur ${instrument} Player`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    c.stress = Math.max(0, (c.stress ?? 0) - 5);
    record.achievements = [...achievements, `Amateur ${instrument} Player`];

    return {
      message: `You're now an amateur ${instrument} player! You can play simple songs and you're starting to sound decent.`,
      statChanges: { happiness: 20, stress: -5 },
      achievement: `Amateur ${instrument} Player`,
      scheduleNextCheck: {
        daysFromNow: 90,
        title: `${instrument} Progress`,
        message: `Progressing with ${instrument}`,
      },
    };
  } else {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 10);
    c.stress = Math.max(0, (c.stress ?? 0) - 5);

    if (focus === 'Slack Off') {
      return {
        message: `You're not practicing the ${instrument} much. Without consistent practice, it's hard to improve.`,
        statChanges: { happiness: 10, stress: -5 },
        scheduleNextCheck: {
          daysFromNow: 90,
          title: `${instrument} Progress`,
          message: `Building skills on ${instrument}`,
        },
      };
    }

    return {
      message: `You're making steady progress with the ${instrument}. Your fingers are getting more comfortable with the movements.`,
      statChanges: { happiness: 10, stress: -5 },
      scheduleNextCheck: {
        daysFromNow: 90,
        title: `${instrument} Progress`,
        message: `Building skills on ${instrument}`,
      },
    };
  }
}

/**
 * Process cooking class progress
 */
export function cookingClassProgress(
  player: Player,
  cookingRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === cookingRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const focusMap: Record<FocusType, number> = {
    'Work Hard': 15,
    'Balanced': 10,
    'Slack Off': 3,
    'Socialize': 12, // Cooking classes are social!
  };

  let progressGain = focusMap[focus];

  // Self-taught progresses slower
  if (record.type === 'cooking_self_taught') {
    progressGain = Math.floor(progressGain * 0.6);
  }

  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const classType = record.level ?? 'cooking';
  const achievements = record.achievements ?? [];

  // Skill levels: 0-24 Novice, 25-49 Competent, 50-74 Proficient, 75-89 Expert, 90-100 Master Chef

  if (record.performance >= 90 && !achievements.includes(`Master Chef - ${classType}`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 45);
    c.social = Math.min(100, (c.social ?? 50) + 25);
    c.prestige = (c.prestige ?? 0) + 15;
    record.achievements = [...achievements, `Master Chef - ${classType}`];

    // Could potentially start a food-related side business
    let bonusMessage = '';
    if (Math.random() < 0.2) {
      const sideIncome = Math.floor(Math.random() * 151) + 150;
      c.money = (c.money ?? 0) + sideIncome;
      bonusMessage = ` Your cooking skills are so good that you've started earning money from catering or selling baked goods! You made $${sideIncome} this month.`;
    }

    return {
      message: `You've become a master chef in ${classType}! Your dishes are restaurant-quality. Friends and family rave about your cooking, and you save money by cooking amazing meals at home.${bonusMessage}`,
      statChanges: { happiness: 45, social: 25, prestige: 15 },
      achievement: `Master Chef - ${classType}`,
      completed: true,
    };
  } else if (record.performance >= 75 && !achievements.includes(`Expert Cook - ${classType}`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 30);
    c.social = Math.min(100, (c.social ?? 50) + 15);
    record.achievements = [...achievements, `Expert Cook - ${classType}`];

    return {
      message: `You've become an expert in ${classType}! You can prepare complex dishes with confidence and people love when you cook for them.`,
      statChanges: { happiness: 30, social: 15 },
      achievement: `Expert Cook - ${classType}`,
      scheduleNextCheck: {
        daysFromNow: 56,
        title: 'Cooking Progress',
        message: `Continuing to master ${classType}`,
      },
    };
  } else if (record.performance >= 50 && !achievements.includes(`Proficient Cook - ${classType}`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
    c.social = Math.min(100, (c.social ?? 50) + 10);
    c.money = (c.money ?? 0) + 30; // Save money by cooking better meals
    record.achievements = [...achievements, `Proficient Cook - ${classType}`];

    return {
      message: `You're now proficient in ${classType}! You can cook a variety of dishes well and enjoy experimenting with recipes.`,
      statChanges: { happiness: 25, social: 10, money: 30 },
      achievement: `Proficient Cook - ${classType}`,
      scheduleNextCheck: {
        daysFromNow: 56,
        title: 'Cooking Progress',
        message: `Advancing in ${classType}`,
      },
    };
  } else if (record.performance >= 25 && !achievements.includes(`Competent Cook - ${classType}`)) {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    c.social = Math.min(100, (c.social ?? 50) + 5);
    c.money = (c.money ?? 0) + 20; // Save a bit on food
    record.achievements = [...achievements, `Competent Cook - ${classType}`];

    return {
      message: `You're becoming a competent cook in ${classType}! You can follow recipes successfully and your meals are consistently good.`,
      statChanges: { happiness: 20, social: 5, money: 20 },
      achievement: `Competent Cook - ${classType}`,
      scheduleNextCheck: {
        daysFromNow: 42,
        title: 'Cooking Progress',
        message: `Building skills in ${classType}`,
      },
    };
  } else {
    c.happiness = Math.min(100, (c.happiness ?? 50) + 10);

    if (focus === 'Slack Off') {
      return {
        message: `You're not putting much effort into your ${classType} classes. Without practice, it's hard to improve your cooking.`,
        statChanges: { happiness: 10 },
        scheduleNextCheck: {
          daysFromNow: 42,
          title: 'Cooking Progress',
          message: `Continuing ${classType} classes`,
        },
      };
    }

    return {
      message: `You're learning the basics of ${classType}. Every class teaches you something new!`,
      statChanges: { happiness: 10 },
      scheduleNextCheck: {
        daysFromNow: 42,
        title: 'Cooking Progress',
        message: `Continuing ${classType} classes`,
      },
    };
  }
}

// =============================================================================
// Physical Activity Progress Functions
// =============================================================================

/**
 * Process soccer team progress
 */
export function soccerProgress(
  player: Player,
  activityRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === activityRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = PHYSICAL_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  if (record.performance >= 70) {
    c.health = Math.min(100, (c.health ?? 100) + 10);
    c.social = Math.min(100, (c.social ?? 50) + 15);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);

    return {
      message: "You're becoming one of the best players on the soccer team! Your dedication is paying off.",
      statChanges: { health: 10, social: 15, happiness: 20 },
    };
  } else if (record.performance >= 40) {
    c.health = Math.min(100, (c.health ?? 100) + 5);
    c.social = Math.min(100, (c.social ?? 50) + 10);

    return {
      message: "Soccer practice is going well. You're making steady progress and enjoying being part of the team.",
      statChanges: { health: 5, social: 10 },
    };
  } else {
    c.health = Math.min(100, (c.health ?? 100) + 3);

    return {
      message: "You're struggling at soccer practice, but the exercise is good for you. Keep trying!",
      statChanges: { health: 3 },
    };
  }
}

/**
 * Process martial arts progress
 */
export function martialArtsProgress(
  player: Player,
  activityRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === activityRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = PHYSICAL_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const achievements = record.achievements ?? [];

  if (record.performance >= 70 && !achievements.includes('Belt Advancement')) {
    c.health = Math.min(100, (c.health ?? 100) + 10);
    c.intelligence = Math.min(100, (c.intelligence ?? 50) + 5);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    record.achievements = [...achievements, 'Belt Advancement'];

    return {
      message: "Your sensei says you're ready to test for your next belt! Your dedication to martial arts is impressive.",
      statChanges: { health: 10, intelligence: 5, happiness: 20 },
      achievement: 'Belt Advancement',
    };
  } else if (record.performance >= 40) {
    c.health = Math.min(100, (c.health ?? 100) + 7);
    c.stress = Math.max(0, (c.stress ?? 0) - 10);

    return {
      message: "Your martial arts training is going well. You're developing discipline and skill.",
      statChanges: { health: 7, stress: -10 },
    };
  } else {
    c.health = Math.min(100, (c.health ?? 100) + 5);

    return {
      message: "The martial arts forms are challenging, but you're learning. Keep practicing!",
      statChanges: { health: 5 },
    };
  }
}

/**
 * Process running progress
 */
export function runningProgress(
  player: Player,
  activityRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === activityRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = PHYSICAL_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const achievements = record.achievements ?? [];

  if (record.performance >= 70 && !achievements.includes('5K Runner')) {
    c.health = Math.min(100, (c.health ?? 100) + 15);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 25);
    c.stress = Math.max(0, (c.stress ?? 0) - 15);
    record.achievements = [...achievements, '5K Runner'];

    return {
      message: "You're in great running shape! You completed your first 5K race! What an accomplishment!",
      statChanges: { health: 15, happiness: 25, stress: -15 },
      achievement: '5K Runner',
    };
  } else if (record.performance >= 40) {
    c.health = Math.min(100, (c.health ?? 100) + 10);
    c.stress = Math.max(0, (c.stress ?? 0) - 10);

    return {
      message: "Your running routine is going well. You're making steady progress and feeling healthier.",
      statChanges: { health: 10, stress: -10 },
    };
  } else {
    c.health = Math.min(100, (c.health ?? 100) + 5);

    if (focus === 'Slack Off') {
      return {
        message: "Running is harder than you thought. Consider slowing down to build stamina gradually.",
        statChanges: { health: 5 },
      };
    }

    return {
      message: "Building your running endurance takes time. Keep at it!",
      statChanges: { health: 5 },
    };
  }
}

/**
 * Process gym progress
 */
export function gymProgress(
  player: Player,
  activityRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === activityRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = PHYSICAL_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const achievements = record.achievements ?? [];

  if (record.performance >= 70 && !achievements.includes('Fitness Enthusiast')) {
    c.health = Math.min(100, (c.health ?? 100) + 15);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    c.stress = Math.max(0, (c.stress ?? 0) - 15);
    record.achievements = [...achievements, 'Fitness Enthusiast'];

    return {
      message: "You're in great shape! The gym is really paying off! You feel strong and confident.",
      statChanges: { health: 15, happiness: 20, stress: -15 },
      achievement: 'Fitness Enthusiast',
    };
  } else if (record.performance >= 40) {
    c.health = Math.min(100, (c.health ?? 100) + 10);
    c.stress = Math.max(0, (c.stress ?? 0) - 10);

    return {
      message: "Your gym workouts are going well. You're seeing steady improvement!",
      statChanges: { health: 10, stress: -10 },
    };
  } else {
    c.health = Math.min(100, (c.health ?? 100) + 5);

    return {
      message: "You're not seeing the gym results you hoped for. Consider hiring a trainer or watching technique videos.",
      statChanges: { health: 5 },
    };
  }
}

/**
 * Process yoga progress
 */
export function yogaProgress(
  player: Player,
  activityRecordId: string
): ProgressResult | null {
  const c = player.c;
  const record = c.activityRecords?.find((r) => r.id === activityRecordId);

  if (!record) return null;

  const focus = (record.focus as FocusType) ?? 'Balanced';
  const progressGain = PHYSICAL_FOCUS_MAP[focus];
  record.performance = Math.min(100, (record.performance ?? 0) + progressGain);

  const achievements = record.achievements ?? [];

  if (record.performance >= 70 && !achievements.includes('Yoga Practitioner')) {
    c.health = Math.min(100, (c.health ?? 100) + 12);
    c.happiness = Math.min(100, (c.happiness ?? 50) + 20);
    c.stress = Math.max(0, (c.stress ?? 0) - 25);
    record.achievements = [...achievements, 'Yoga Practitioner'];

    return {
      message: "You've become quite skilled at yoga! Your practice has deepened and you feel more balanced and peaceful.",
      statChanges: { health: 12, happiness: 20, stress: -25 },
      achievement: 'Yoga Practitioner',
    };
  } else if (record.performance >= 40) {
    c.health = Math.min(100, (c.health ?? 100) + 8);
    c.stress = Math.max(0, (c.stress ?? 0) - 15);

    return {
      message: "Your yoga practice is going well. You're feeling more flexible and centered.",
      statChanges: { health: 8, stress: -15 },
    };
  } else {
    c.health = Math.min(100, (c.health ?? 100) + 5);
    c.stress = Math.max(0, (c.stress ?? 0) - 10);

    return {
      message: "Some of the yoga poses are challenging. Be patient with yourself - yoga is about progress, not perfection.",
      statChanges: { health: 5, stress: -10 },
    };
  }
}

// =============================================================================
// Game Loop Integration
// =============================================================================

/**
 * Learning activity types for continuous progress updates
 */
const LEARNING_ACTIVITY_TYPES = [
  'online_course',
  'online_course_free',
  'language_learning',
  'language_learning_app',
  'coding_bootcamp',
  'coding_bootcamp_parttime',
  'music_lessons',
  'music_self_taught',
  'cooking_classes',
  'cooking_self_taught',
];

/**
 * Physical activity types for continuous progress updates
 */
const PHYSICAL_ACTIVITY_TYPES = [
  'physical_activity',
  'soccer',
  'martial_arts',
  'running',
  'gym',
  'yoga',
];

/**
 * Handle learning activities during game loop
 * Updates performance based on focus level
 *
 * Performance modifiers by focus:
 * - Work Hard: +1 per tick (faster learning)
 * - Balanced: +0.5 per tick (steady learning)
 * - Slack Off: +0.1 per tick (minimal learning)
 * - Socialize: +0.3 per tick (some learning, but distracted)
 */
export function handleLearningActivities(player: Player, person: Person): void {
  const records = person.activityRecords ?? [];

  for (const record of records) {
    if (LEARNING_ACTIVITY_TYPES.includes(record.type)) {
      const focus = (record.focus as FocusType) ?? 'Balanced';

      let performanceGain: number;
      switch (focus) {
        case 'Work Hard':
          performanceGain = 1;
          break;
        case 'Balanced':
          performanceGain = 0.5;
          break;
        case 'Socialize':
          performanceGain = 0.3;
          break;
        case 'Slack Off':
          performanceGain = 0.1;
          break;
        default:
          performanceGain = 0.5;
      }

      record.performance = Math.min(100, (record.performance ?? 0) + performanceGain);
    }
  }
}

/**
 * Handle physical activities during game loop
 * Updates performance based on focus level
 */
export function handlePhysicalActivities(player: Player, person: Person): void {
  const records = person.activityRecords ?? [];

  for (const record of records) {
    if (PHYSICAL_ACTIVITY_TYPES.includes(record.type)) {
      const focus = (record.focus as FocusType) ?? 'Balanced';

      let performanceGain: number;
      switch (focus) {
        case 'Work Hard':
          performanceGain = 0.8;
          break;
        case 'Balanced':
          performanceGain = 0.4;
          break;
        case 'Socialize':
          performanceGain = 0.3;
          break;
        case 'Slack Off':
          performanceGain = 0.1;
          break;
        default:
          performanceGain = 0.4;
      }

      record.performance = Math.min(100, (record.performance ?? 0) + performanceGain);

      // Physical activities also slowly improve health
      if (focus !== 'Slack Off') {
        person.health = Math.min(100, (person.health ?? 100) + 0.05);
      }
    }
  }
}

/**
 * Handle all activity progress during game loop
 * Called periodically to update all activity records
 */
export function handleAllActivityProgress(player: Player): void {
  // Track milestones reached this tick for player character
  const milestones = handleActivitiesWithMilestones(player, player.c);

  // Queue milestone messages
  for (const milestone of milestones) {
    player.messageQueue = player.messageQueue ?? [];
    player.messageQueue.push(milestone.message);
  }

  // Also update relationship NPCs' activities (no milestone notifications for NPCs)
  for (const person of player.r ?? []) {
    handleLearningActivities(player, person);
    handlePhysicalActivities(player, person);
  }
}

/**
 * Handle activities with milestone tracking
 * Returns array of milestone notifications
 */
function handleActivitiesWithMilestones(
  player: Player,
  person: Person
): Array<{ message: string; achievement?: string }> {
  const milestones: Array<{ message: string; achievement?: string }> = [];
  const records = person.activityRecords ?? [];

  // Define milestone thresholds
  const MILESTONES = [25, 50, 75, 100];

  for (const record of records) {
    const oldPerformance = record.performance ?? 0;
    let newPerformance = oldPerformance;

    // Apply progress based on activity type
    if (LEARNING_ACTIVITY_TYPES.includes(record.type)) {
      const focus = (record.focus as FocusType) ?? 'Balanced';
      let performanceGain: number;
      switch (focus) {
        case 'Work Hard':
          performanceGain = 1;
          break;
        case 'Balanced':
          performanceGain = 0.5;
          break;
        case 'Socialize':
          performanceGain = 0.3;
          break;
        case 'Slack Off':
          performanceGain = 0.1;
          break;
        default:
          performanceGain = 0.5;
      }
      newPerformance = Math.min(100, oldPerformance + performanceGain);
    } else if (PHYSICAL_ACTIVITY_TYPES.includes(record.type)) {
      const focus = (record.focus as FocusType) ?? 'Balanced';
      let performanceGain: number;
      switch (focus) {
        case 'Work Hard':
          performanceGain = 0.8;
          break;
        case 'Balanced':
          performanceGain = 0.4;
          break;
        case 'Socialize':
          performanceGain = 0.3;
          break;
        case 'Slack Off':
          performanceGain = 0.1;
          break;
        default:
          performanceGain = 0.4;
      }
      newPerformance = Math.min(100, oldPerformance + performanceGain);

      // Physical activities also slowly improve health
      if (focus !== 'Slack Off') {
        person.health = Math.min(100, (person.health ?? 100) + 0.05);
      }
    } else if (record.type === 'extracurricular') {
      // Extracurricular activities also gain progress
      const focus = (record.focus as FocusType) ?? 'Balanced';
      const multiplier = FOCUS_MODIFIERS[focus] ?? 0.7;
      newPerformance = Math.min(100, oldPerformance + (0.5 * multiplier));
    }

    // Update performance
    record.performance = newPerformance;

    // Check for milestone crossings
    for (const milestone of MILESTONES) {
      if (oldPerformance < milestone && newPerformance >= milestone) {
        const activityName = getActivityNameFromRecord(record, person);
        const milestoneMessage = getMilestoneMessage(activityName, milestone);
        milestones.push({
          message: milestoneMessage,
          achievement: `${activityName} - ${milestone}%`,
        });

        // Add to achievements if not already there
        record.achievements = record.achievements ?? [];
        const achievementName = `${milestone}% Progress`;
        if (!record.achievements.includes(achievementName)) {
          record.achievements.push(achievementName);
        }
      }
    }
  }

  return milestones;
}

/**
 * Get activity name from record by finding matching activity
 */
function getActivityNameFromRecord(
  record: ActivityRecordData,
  person: Person
): string {
  // Try to find matching activity
  const activity = (person.activities ?? []).find(
    (a: { id?: string; title?: string }) => a.id === record.id
  ) as { title?: string } | undefined;

  if (activity?.title) {
    return activity.title;
  }

  // Fallback to type with nice formatting
  return record.type
    .replace(/_/g, ' ')
    .replace(/\b\w/g, (c) => c.toUpperCase());
}

/**
 * Get milestone notification message
 */
function getMilestoneMessage(activityName: string, milestone: number): string {
  switch (milestone) {
    case 25:
      return `You're making progress in ${activityName}! You've reached 25% proficiency.`;
    case 50:
      return `Halfway there! You've reached 50% proficiency in ${activityName}.`;
    case 75:
      return `You're becoming skilled at ${activityName}! 75% proficiency reached.`;
    case 100:
      return `Congratulations! You've mastered ${activityName}! 100% proficiency achieved!`;
    default:
      return `You've reached ${milestone}% in ${activityName}.`;
  }
}

// =============================================================================
// Progress Event Registry
// =============================================================================

/**
 * Map of progress function names to their implementations
 * Used by OneTimeEvent completionFunc resolution
 */
export const progressEventRegistry: Record<
  string,
  (player: Player, ...args: unknown[]) => ProgressResult | null
> = {
  onlineCourseProgress: (player, args) => {
    const { course_record_id } = (args as Record<string, string>) ?? {};
    return onlineCourseProgress(player, course_record_id);
  },
  languageLearningProgress: (player, args) => {
    const { language_record_id } = (args as Record<string, string>) ?? {};
    return languageLearningProgress(player, language_record_id);
  },
  codingBootcampProgress: (player, args) => {
    const { bootcamp_record_id, stage } = (args as Record<string, string>) ?? {};
    return codingBootcampProgress(player, bootcamp_record_id, stage as 'midpoint' | 'completion');
  },
  musicLessonsProgress: (player, args) => {
    const { music_record_id } = (args as Record<string, string>) ?? {};
    return musicLessonsProgress(player, music_record_id);
  },
  cookingClassProgress: (player, args) => {
    const { cooking_record_id } = (args as Record<string, string>) ?? {};
    return cookingClassProgress(player, cooking_record_id);
  },
  soccerProgress: (player, args) => {
    const { activity_record_id } = (args as Record<string, string>) ?? {};
    return soccerProgress(player, activity_record_id);
  },
  martialArtsProgress: (player, args) => {
    const { activity_record_id } = (args as Record<string, string>) ?? {};
    return martialArtsProgress(player, activity_record_id);
  },
  runningProgress: (player, args) => {
    const { activity_record_id } = (args as Record<string, string>) ?? {};
    return runningProgress(player, activity_record_id);
  },
  gymProgress: (player, args) => {
    const { activity_record_id } = (args as Record<string, string>) ?? {};
    return gymProgress(player, activity_record_id);
  },
  yogaProgress: (player, args) => {
    const { activity_record_id } = (args as Record<string, string>) ?? {};
    return yogaProgress(player, activity_record_id);
  },
};

/**
 * Execute a progress event by name
 */
export function executeProgressEvent(
  player: Player,
  eventName: string,
  args: Record<string, unknown>
): ProgressResult | null {
  const handler = progressEventRegistry[eventName];
  if (handler) {
    const result = handler(player, args);

    // If result has a scheduled next check, create the one-time event
    if (result?.scheduleNextCheck) {
      scheduleProgressCheck(
        player.c,
        result.scheduleNextCheck.title,
        result.scheduleNextCheck.message,
        result.scheduleNextCheck.daysFromNow,
        eventName,
        args
      );
    }

    // Add message to player's message queue
    if (result?.message) {
      player.messageQueue = player.messageQueue ?? [];
      player.messageQueue.push(result.message);
    }

    return result;
  }
  return null;
}

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

export {
  // Types are already exported above

  // Constants
  LEARNING_ACTIVITY_TYPES,
  PHYSICAL_ACTIVITY_TYPES,
  FOCUS_MODIFIERS,
  LEARNING_FOCUS_MAP,
  PHYSICAL_FOCUS_MAP,
};
