/**
 * Character Manager Service
 * Handles character creation and management for BaoLife
 * Ported from Python character/character_manager.py
 */

import { v4 as uuidv4 } from 'uuid';
import { Person, PersonData, Sex } from '../../models/Person.js';
import { Player, RelationshipData } from '../../models/Player.js';
import { getFirstname, getLastname, getOppositeSex, getRandomSex } from './names.js';
import { setAvatar, generateAvatarSettings, AvatarSettings } from './avatar.js';
import { createRelationship } from '../relationships/relationship_manager.js';
import { setEducation } from '../education/education_manager.js';
import { setHabits } from '../health/habit_manager.js';

// ============================================================
// Character Description Functions
// ============================================================

/**
 * Generate a human-readable description of a person based on their attributes
 */
export function generatePersonDescription(person: Person): string {
  let description = `${person.firstname} ${person.lastname} is a ${person.sex.toLowerCase()}.`;

  for (const rel of person.relationships) {
    description += ` They are your ${rel}. `;
  }

  if (person.familiarity > 0) {
    if (person.ageYears !== undefined) {
      description += ` They are ${person.ageYears} years old`;
    }
    if (person.job?.title) {
      description += `, and work as a ${person.job.title}.`;
    }
  }

  if (person.familiarity > 20 && person.education) {
    description += ` They have a ${person.education} level of education`;
    if (person.college) {
      description += `, and graduated from ${person.college}.`;
    }
  }

  if (person.familiarity > 40) {
    if (person.likes && person.likes.length > 0) {
      description += `. Their interests include ${person.likes.join(', ')}`;
    }
    if (person.dislikes && person.dislikes.length > 0) {
      description += `, but they dislike ${person.dislikes.join(', ')}.`;
    }
  }

  if (person.familiarity > 80) {
    if (person.job?.income) {
      description += `. They earn approximately ${person.job.income} per month from their job`;
    }
    if (person.money > 0) {
      description += `, and have about ${person.money} in savings.`;
    }
  }

  return description;
}

/**
 * Generate an OpenAI-formatted description for AI conversation prompts
 */
export function generateOpenAIDescription(person: Person): string {
  let description = `Pretend you are ${person.firstname} ${person.lastname}, a ${person.sex.toLowerCase()}`;

  // Check for romantic relationships
  const romanticRelationships = ['dating_match', 'partner', 'dating', 'girlfriend', 'boyfriend', 'spouse', 'wife', 'husband', 'fiancé', 'fiancée', 'engaged'];
  const romanticRel = person.relationships.find(rel => romanticRelationships.includes(rel.toLowerCase()));

  // Check for ex relationship first - this takes priority
  const isEx = person.relationships.some(rel => rel.toLowerCase() === 'ex');

  if (isEx) {
    description += `. You are their ex - you used to date but the relationship is over. Be polite but distant. You're not hostile, but there's an awkwardness between you. Don't be flirty or romantic - that chapter is closed. Keep conversations casual and brief. You might still care about them as a person, but you're not interested in rekindling anything. If they try to flirt or be romantic, gently deflect or change the subject. You've both moved on (or are trying to).`;
  } else if (romanticRel) {
    const relLower = romanticRel.toLowerCase();
    if (relLower === 'dating_match') {
      description += `. You matched with them on a dating app and you're both interested in each other. Be flirty and playful! Match their energy - if they're being romantic or suggestive, lean into it and flirt back. Don't deflect or change topics when things get flirty. You're attracted to them and enjoying the conversation. Only pull back if they're genuinely rude or disrespectful.`;
    } else if (['spouse', 'wife', 'husband'].includes(relLower)) {
      description += `. You are their ${romanticRel} - you're married and deeply in love. Be affectionate, flirty, and intimate. You know each other well and are comfortable being romantic. Match their energy and don't shy away from playful or suggestive conversation.`;
    } else if (['fiancé', 'fiancée', 'engaged'].includes(relLower)) {
      description += `. You are their ${romanticRel} - you're engaged to be married! Be loving, excited about your future together, and comfortably flirty. Match their romantic energy.`;
    } else {
      // girlfriend, boyfriend, partner, dating
      description += `. You are their ${romanticRel} - you're in a relationship and really into each other. Be flirty and affectionate! Match their energy - if they're being romantic or suggestive, lean into it. You're attracted to them and enjoy the intimacy of your relationship.`;
    }
  } else {
    // Handle specific relationship types with appropriate context
    for (const rel of person.relationships) {
      const relLower = rel.toLowerCase();

      // Authority figures - professional boundaries
      if (['teacher', 'professor', 'instructor'].includes(relLower)) {
        description += `. You are their ${rel} - maintain a professional, supportive but authoritative tone. You care about their education and growth. Be encouraging but appropriate. Don't be too casual or act like their friend. You can be warm but keep professional boundaries.`;
      }
      else if (['boss', 'manager', 'supervisor'].includes(relLower)) {
        description += `. You are their ${rel} at work - be professional and respectful. You have authority but should be fair. Keep conversations work-appropriate. You can be friendly but maintain professional distance.`;
      }
      else if (['coach', 'mentor'].includes(relLower)) {
        description += `. You are their ${rel} - be motivating and supportive. Push them to be better but be encouraging. You're invested in their success and growth.`;
      }
      else if (['doctor', 'therapist', 'counselor'].includes(relLower)) {
        description += `. You are their ${rel} - be professional, caring, and helpful. Focus on their wellbeing. Maintain appropriate professional boundaries while being warm and supportive.`;
      }
      // Family - loving but with family dynamics
      else if (['mother', 'mom', 'father', 'dad', 'parent'].includes(relLower)) {
        description += `. You are their ${rel} - be loving, supportive, but also parental. You care deeply about them. You might give advice (wanted or not), ask about their life, and show concern for their wellbeing. Be warm but you're still their parent, not their friend.`;
      }
      else if (['grandmother', 'grandma', 'grandfather', 'grandpa', 'grandparent'].includes(relLower)) {
        description += `. You are their ${rel} - be warm, loving, and a bit doting. You adore them and love hearing about their life. You might share wisdom or stories from your past. Be affectionate and supportive.`;
      }
      else if (['brother', 'sister', 'sibling'].includes(relLower)) {
        description += `. You are their ${rel} - be casual and comfortable. You can tease each other, bicker playfully, or be supportive depending on the mood. You know each other well and have that sibling dynamic.`;
      }
      else if (['aunt', 'uncle'].includes(relLower)) {
        description += `. You are their ${rel} - be friendly and supportive. You're family but not their parent, so you can be a bit more relaxed. Show interest in their life.`;
      }
      else if (['cousin'].includes(relLower)) {
        description += `. You are their ${rel} - be casual and friendly. You're family but peers, so keep it relaxed and fun.`;
      }
      // Peers and friends
      else if (['best friend', 'bestfriend', 'bff'].includes(relLower)) {
        description += `. You are their best friend - be super comfortable, supportive, and real with them. You can joke around, be honest, and share everything. You've got their back no matter what.`;
      }
      else if (['friend'].includes(relLower)) {
        description += `. You are their friend - be friendly, supportive, and casual. You enjoy talking to them and care about what's going on in their life.`;
      }
      else if (['classmate'].includes(relLower)) {
        description += `. You are their classmate - you're peers at school. Be casual and relatable. You might talk about school, classes, or just hang out topics.`;
      }
      else if (['coworker', 'colleague'].includes(relLower)) {
        description += `. You are their coworker - be friendly but keep it somewhat professional. You might chat about work, office stuff, or casual topics. You're not super close but you're on good terms.`;
      }
      else if (['neighbor'].includes(relLower)) {
        description += `. You are their neighbor - be friendly and polite. You're not super close but you're on good terms. Keep it casual and neighborly.`;
      }
      else if (['acquaintance', 'stranger'].includes(relLower)) {
        description += `. You are an acquaintance - be polite but you don't know them well. Keep it friendly but a bit more formal since you're still getting to know each other.`;
      }
      // Crush - romantic interest but not dating yet
      else if (['crush'].includes(relLower)) {
        description += `. You have a crush on them - you're attracted to them and nervous/excited when talking to them. Be a bit flirty but also a little shy. You want them to like you back.`;
      }
      // Child relationship (player is the parent)
      else if (['child', 'son', 'daughter'].includes(relLower)) {
        description += `. They are your parent - be respectful but also comfortable. You might ask for advice, share what's happening in your life, or just chat. You love them even if you don't always show it.`;
      }
      // Extended family grandparents
      else if (relLower.includes('grandmother') || relLower.includes('grandma')) {
        description += `. You are their grandmother - be warm, loving, and a bit doting. You adore them and love hearing about their life. You might share wisdom or stories from your past. Be affectionate and supportive.`;
      }
      else if (relLower.includes('grandfather') || relLower.includes('grandpa')) {
        description += `. You are their grandfather - be warm and wise. You enjoy spending time with them and might share stories or life lessons. Be supportive and show interest in their life.`;
      }
      // Generic family tag - skip if more specific relationship exists
      else if (['family'].includes(relLower)) {
        // Don't add anything for generic 'family' tag - let specific relationship handle it
        continue;
      }
      // Default for unknown relationship types
      else {
        description += `. You are a ${rel} to the conversation partner. Behave appropriately for this relationship.`;
      }
    }
  }

  if (person.ageYears !== undefined) {
    description += ` You're ${person.ageYears} years old`;
  }
  if (person.job?.title) {
    description += `, a ${person.job.title}.`;
  }

  if (person.mood !== undefined) {
    // Mood is now a string like "Calm", "Stressed", "Happy", etc.
    const moodText = person.mood.toLowerCase();
    description += ` and you are ${moodText}.`;
  }

  if (person.education) {
    description += ` you studied ${person.education}`;
    if (person.college) {
      description += ` at ${person.college}.`;
    }
  }

  if (person.likes && person.likes.length > 0) {
    description += `. you like ${person.likes.join(', ')}`;
  }
  if (person.dislikes && person.dislikes.length > 0) {
    description += ` & dislike ${person.dislikes.join(', ')}.`;
  }

  if (person.job?.income) {
    description += `. you earn ${person.job.income}/mo`;
  }
  if (person.money > 0) {
    description += ` & have ${person.money} saved.`;
  }

  return description;
}

// ============================================================
// Birthday Functions
// ============================================================

/**
 * Set a person's birthday based on their age in days and current date
 */
export function setBirthday(person: Person, player: Player): void {
  if (person.ageDays) {
    const currentDate = new Date();
    // Parse MM-DD format
    const [month, day] = player.date.split('-').map((n) => parseInt(n, 10));
    currentDate.setMonth(month - 1);
    currentDate.setDate(day);

    const birthday = new Date(currentDate);
    birthday.setDate(birthday.getDate() - person.ageDays);

    // Format as MM-DD
    const birthMonth = String(birthday.getMonth() + 1).padStart(2, '0');
    const birthDay = String(birthday.getDate()).padStart(2, '0');
    person.birthday = `${birthMonth}-${birthDay}`;
  }
}

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

/**
 * Random integer between min and max (inclusive)
 */
function rand(min: number, max: number): number {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
 * Create a base person object with default values
 */
function createBasePerson(sex?: Sex): Person {
  const personSex = sex ?? getRandomSex();
  const data: PersonData = {
    id: uuidv4(),
    firstname: getFirstname(personSex),
    lastname: getLastname(),
    sex: personSex,
    status: 'alive',
    relationships: [],
    familiarity: 0,
    ageDays: 0,
    ageYears: 0,
    mood: 'Calm',
    affinity: 50,
    money: 0,
    diamonds: 0,
    prestige: 0,
    happiness: 50,
    health: 100,
    energy: 100,
    intelligence: 50,
    social: 50,
    stress: 0,
    creativity: 50,
  };
  return new Person(data);
}

/**
 * Set all default values for a character
 */
export function setValues(player: Player, person: Person): Person {
  // Set avatar
  const settings = generateAvatarSettings(person);
  (person as unknown as { avatar_settings: AvatarSettings }).avatar_settings = settings;
  setAvatar(person);

  // Set birthday
  setBirthday(person, player);

  // Set ACT score for adults
  if (person.ageYears >= 18) {
    (person as unknown as { actScore: number }).actScore = rand(10, 36);
  }

  // Set random likes and dislikes
  const allInterests = [
    'music', 'sports', 'reading', 'gaming', 'cooking', 'travel',
    'art', 'movies', 'nature', 'technology', 'fashion', 'fitness',
  ];
  person.likes = [];
  person.dislikes = [];

  // Random likes (2-4)
  const numLikes = rand(2, 4);
  const shuffled = [...allInterests].sort(() => Math.random() - 0.5);
  for (let i = 0; i < numLikes && i < shuffled.length; i++) {
    person.likes.push(shuffled[i]);
  }

  // Random dislikes (1-2) from remaining
  const numDislikes = rand(1, 2);
  for (let i = numLikes; i < numLikes + numDislikes && i < shuffled.length; i++) {
    person.dislikes.push(shuffled[i]);
  }

  return person;
}

// ============================================================
// Family Creation Functions
// ============================================================

/**
 * Create a partner (boyfriend/girlfriend) for the player character
 */
export function getPartner(player: Player): Player {
  const partnerSex = getOppositeSex(player.c.sex);
  const partner = createBasePerson(partnerSex);

  partner.relationships.push('partner');
  if (partnerSex === 'Female') {
    (partner as unknown as { title: string }).title = 'Girlfriend';
  } else {
    (partner as unknown as { title: string }).title = 'Boyfriend';
  }

  partner.firstname = getFirstname(partnerSex);
  partner.lastname = getLastname();
  // Content safety: romantic partners are adults only (18+). Floor the generated
  // age at 18 so a romantic partner is never created under 18, regardless of the
  // player's age. (Caller is also gated at player age >= 18.)
  partner.ageYears = Math.max(18, player.c.ageYears + rand(-3, 3));
  partner.ageDays = partner.ageYears * 365 + rand(1, 365);

  setValues(player, partner);
  player.r.unshift(partner);
  player.c.partner = partner.id;

  // Create relationship entry for relData (required for frontend DatingView)
  const rel = createRelationship(player.c.id, partner.id, player.date, 'Dating', 'You are dating!');
  (player.c as unknown as { relationship: string }).relationship = rel.id;
  (partner as unknown as { relationship: string }).relationship = rel.id;
  player.relData.push(rel as unknown as RelationshipData);

  return player;
}

/**
 * Create a child for the player character
 */
export function addChild(player: Player): Person {
  const child = createBasePerson();

  child.relationships.push('child');
  child.relationships.push('family');
  child.familyLevel = 1;

  if (child.sex === 'Male') {
    (child as unknown as { title: string }).title = 'Son';
  } else {
    (child as unknown as { title: string }).title = 'Daughter';
  }

  child.lastname = player.c.lastname;
  child.ageYears = 0;
  child.ageDays = 0;
  child.ageHours = 0;

  setValues(player, child);
  player.r.unshift(child);

  return child;
}

/**
 * If the player's pregnancy has reached term, deliver the baby: create a real
 * child Person (lights up inheritance/heir/legacy + all `child`-gated parenting
 * content), clear the pregnancy state, and queue the `child_born` lifecycle
 * event so the achievement/life-goal credit fires AT birth (drained by both the
 * online PlayerSession and the offline LoopManager).
 *
 * Runs on a daily tick on BOTH loops. Idempotent: it clears `pregnant` the
 * instant it fires, so a baby is delivered exactly once per pregnancy.
 *
 * Returns the birth message if a child was born this tick, else null.
 */
export function checkPregnancyTerm(player: Player): string | null {
  const c = player.c;
  if (!c || c.status === 'dead') return null;
  if (!c.pregnant) return null;

  const due = c.pregnancyDueDay;
  // Defensive: a pregnancy with no due day set (e.g. legacy save) gets a term
  // ~9 months out from now so it still resolves rather than hanging forever.
  if (due == null) {
    c.pregnancyDueDay = (c.ageDays ?? 0) + 252;
    return null;
  }
  if ((c.ageDays ?? 0) < due) return null;

  const child = addChild(player);

  // Clear pregnancy state so this fires exactly once.
  c.pregnant = false;
  c.pregnancyDueDay = undefined;
  c.tryingForChild = false;

  // Credit the milestone at birth (not at conception). Drained by the online
  // PlayerSession.drainLifecycleQueue and the offline drainLifecycleQueueOffline.
  player.lifecycleQueue = player.lifecycleQueue ?? [];
  player.lifecycleQueue.push({ type: 'child_born' });

  const childWord = (child as unknown as { title?: string }).title ?? 'child';
  const message = `Your ${childWord.toLowerCase()} ${child.firstname} was born! Congratulations on the new arrival.`;
  player.messageQueue = player.messageQueue ?? [];
  player.messageQueue.push(message);

  return message;
}

/**
 * Get the youngest child from player's relationships
 */
export function getYoungestChild(player: Player): Person | null {
  let youngest: Person | null = null;

  for (const r of player.r) {
    if (r.relationships.includes('child')) {
      if (!youngest || r.ageDays < youngest.ageDays) {
        youngest = r;
      }
    }
  }

  return youngest;
}

/**
 * Get the ELDEST living child from the player's relationships — the heir
 * apparent for the generational/legacy system. The eldest child is the one
 * with the greatest ageDays. Dead children are skipped entirely; if no living
 * child exists, the legacy line ends and this returns null.
 *
 * @param player - Player object whose relationships are searched
 * @returns The eldest living child, or null if the player has no living children
 */
export function getEldestLivingChild(player: Player): Person | null {
  let eldest: Person | null = null;

  for (const r of player.r) {
    if (!r.relationships.includes('child')) continue;
    if (r.status !== 'alive') continue;
    if (!eldest || r.ageDays > eldest.ageDays) {
      eldest = r;
    }
  }

  return eldest;
}

/**
 * Create mother and father for the player character
 */
export function addParents(player: Player): Player {
  // Create father
  const father = createBasePerson('Male');
  father.relationships.push('father');
  father.relationships.push('family');
  (father as unknown as { title: string }).title = 'Father';
  father.familyLevel = 1;
  father.lastname = player.c.lastname;
  father.ageYears = player.c.ageYears + rand(18, 34);
  father.ageDays = father.ageYears * 365 + rand(1, 365);
  father.affinity = rand(50, 100);
  setValues(player, father);
  player.r.unshift(father);

  // Create mother
  const mother = createBasePerson('Female');
  mother.relationships.push('mother');
  mother.relationships.push('family');
  (mother as unknown as { title: string }).title = 'Mother';
  mother.familyLevel = 1;
  mother.lastname = player.c.lastname;
  mother.ageYears = player.c.ageYears + rand(18, 34);
  mother.ageDays = mother.ageYears * 365 + rand(1, 365);
  mother.affinity = rand(50, 100);
  setValues(player, mother);
  player.r.unshift(mother);

  return player;
}

/**
 * Create older siblings for the player character (with some randomness)
 */
export function addOlderSiblings(player: Player): Player {
  // 50% chance you have an older sibling
  if (rand(0, 1) === 0) {
    const sibling = createBasePerson();
    sibling.relationships.push('sibling');
    sibling.relationships.push('family');

    if (sibling.sex === 'Male') {
      (sibling as unknown as { title: string }).title = 'Brother';
    } else {
      (sibling as unknown as { title: string }).title = 'Sister';
    }

    sibling.familyLevel = 1;
    sibling.lastname = player.c.lastname;
    sibling.ageYears = player.c.ageYears + rand(0, 3);
    sibling.ageDays = sibling.ageYears * 365 + 270 + rand(1, 365); // at least 9 months older
    setValues(player, sibling);
    player.r.unshift(sibling);

    // 10% chance you have another older sibling
    if (rand(0, 9) === 0) {
      const sibling2 = createBasePerson();
      sibling2.relationships.push('sibling');
      sibling2.relationships.push('family');

      if (sibling2.sex === 'Male') {
        (sibling2 as unknown as { title: string }).title = 'Brother';
      } else {
        (sibling2 as unknown as { title: string }).title = 'Sister';
      }

      sibling2.familyLevel = 1;
      sibling2.lastname = player.c.lastname;
      sibling2.ageYears = sibling.ageYears + rand(1, 3);
      sibling2.ageDays = sibling2.ageYears * 365 + 270 + rand(1, 365);
      setValues(player, sibling2);
      player.r.unshift(sibling2);
    }
  }

  return player;
}

/**
 * Create all four grandparents for the player character
 */
export function addGrandparents(player: Player): Player {
  const father = player.r.find((p) => p.relationships.includes('father'));
  const mother = player.r.find((p) => p.relationships.includes('mother'));

  if (!father || !mother) {
    return player;
  }

  // Paternal grandmother
  const pGrandmother = createBasePerson('Female');
  pGrandmother.relationships.push('paternal_grandmother');
  pGrandmother.relationships.push('family');
  (pGrandmother as unknown as { title: string }).title = 'Grandmother';
  pGrandmother.familyLevel = 2;
  pGrandmother.lastname = player.c.lastname;
  pGrandmother.ageYears = father.ageYears + rand(18, 34);
  pGrandmother.ageDays = pGrandmother.ageYears * 365 + rand(1, 365);
  setValues(player, pGrandmother);
  player.r.unshift(pGrandmother);

  // Paternal grandfather
  const pGrandfather = createBasePerson('Male');
  pGrandfather.relationships.push('paternal_grandfather');
  pGrandfather.relationships.push('family');
  (pGrandfather as unknown as { title: string }).title = 'Grandfather';
  pGrandfather.familyLevel = 2;
  pGrandfather.lastname = player.c.lastname;
  pGrandfather.ageYears = father.ageYears + rand(18, 34);
  pGrandfather.ageDays = pGrandfather.ageYears * 365 + rand(1, 365);
  setValues(player, pGrandfather);
  player.r.unshift(pGrandfather);

  // Maternal grandfather
  const mGrandfather = createBasePerson('Male');
  mGrandfather.relationships.push('maternal_grandfather');
  mGrandfather.relationships.push('family');
  (mGrandfather as unknown as { title: string }).title = 'Grandfather';
  mGrandfather.familyLevel = 2;
  mGrandfather.lastname = getLastname();
  mGrandfather.ageYears = mother.ageYears + rand(18, 34);
  mGrandfather.ageDays = mGrandfather.ageYears * 365 + rand(1, 365);
  setValues(player, mGrandfather);
  player.r.unshift(mGrandfather);

  // Maternal grandmother
  const mGrandmother = createBasePerson('Female');
  mGrandmother.relationships.push('maternal_grandmother');
  mGrandmother.relationships.push('family');
  (mGrandmother as unknown as { title: string }).title = 'Grandmother';
  mGrandmother.familyLevel = 2;
  mGrandmother.lastname = mGrandfather.lastname;
  mGrandmother.ageYears = mother.ageYears + rand(18, 34);
  mGrandmother.ageDays = mGrandmother.ageYears * 365 + rand(1, 365);
  setValues(player, mGrandmother);
  player.r.unshift(mGrandmother);

  return player;
}

// ============================================================
// Friend and Social Character Creation Functions
// ============================================================

/**
 * Create a friend for the player character
 */
export function addFriend(
  player: Player,
  sex: Sex,
  age: 'similar' | 'younger' | 'older' | 'random' = 'similar'
): Player {
  const friend = createBasePerson(sex);
  friend.relationships.push('friend');
  (friend as unknown as { title: string }).title = 'Friend';
  friend.affinity = rand(70, 100);

  if (age === 'similar') {
    friend.ageYears = player.c.ageYears + rand(-1, 1);
  } else if (age === 'younger') {
    friend.ageYears = player.c.ageYears + rand(-6, -1);
  } else if (age === 'older') {
    friend.ageYears = player.c.ageYears + rand(1, 6);
  } else {
    friend.ageYears = player.c.ageYears + rand(-3, 3);
  }

  friend.ageDays = friend.ageYears * 365 + rand(1, 365);
  setValues(player, friend);
  player.r.unshift(friend);

  return player;
}

// ============================================================
// Character Retrieval Functions
// ============================================================

/**
 * Get a random classmate from player's relationships
 */
export function getRandomClassmate(player: Player): Person | null {
  const classmates = player.r.filter((p) => p.relationships.includes('classmate'));

  if (classmates.length === 0) {
    // Create classmates if none exist
    createClassmates(player);
    const newClassmates = player.r.filter((p) => p.relationships.includes('classmate'));
    if (newClassmates.length === 0) return null;
    return newClassmates[rand(0, newClassmates.length - 1)];
  }

  return classmates[rand(0, classmates.length - 1)];
}

/**
 * Get a random friend from player's relationships
 */
export function getRandomFriend(player: Player): Person | null {
  const friends = player.r.filter((p) => p.relationships.includes('friend'));

  if (friends.length === 0) {
    return null;
  }

  return friends[rand(0, friends.length - 1)];
}

/**
 * Get a random character from player's relationships
 */
export function getRandomCharacter(player: Player): Person | null {
  if (player.r.length === 0) {
    return null;
  }
  return player.r[rand(0, player.r.length - 1)];
}

/**
 * Get a random immediate family member (familyLevel == 1)
 */
export function getRandomFamily(player: Player): Person | null {
  const family = player.r.filter((p) => p.familyLevel === 1);

  if (family.length === 0) {
    return null;
  }

  return family[rand(0, family.length - 1)];
}

/**
 * Get all immediate family members (familyLevel == 1)
 */
export function getAllFamily(player: Player): Person[] {
  return player.r.filter((p) => p.familyLevel === 1);
}

// ============================================================
// Generic Character Creation Functions
// ============================================================

/**
 * Create a generic character with customizable attributes
 */
export function createCharacter(
  player: Player,
  sex: Sex | 'random' = 'random',
  age: 'similar' | 'random_adults' | 'random_teens_adults' | 'random' = 'similar',
  relationship: string | 'none' = 'friend'
): Person {
  const personSex = sex === 'random' ? getRandomSex() : sex;
  const newCharacter = createBasePerson(personSex);

  // Set relationship
  if (relationship !== 'none') {
    newCharacter.relationships.push(relationship);
    (newCharacter as unknown as { title: string }).title =
      relationship.charAt(0).toUpperCase() + relationship.slice(1);
  }

  // Set age
  if (age === 'similar') {
    newCharacter.ageYears = player.c.ageYears + rand(0, 1);
  } else if (age === 'random_adults') {
    newCharacter.ageYears = 18 + rand(0, 40);
  } else if (age === 'random_teens_adults') {
    newCharacter.ageYears = 13 + rand(0, 45);
  } else {
    newCharacter.ageYears = rand(5, 60);
  }
  newCharacter.ageDays = newCharacter.ageYears * 365 + rand(1, 270);

  // Set other values
  setValues(player, newCharacter);

  if (relationship === 'none') {
    return newCharacter;
  } else {
    player.r.unshift(newCharacter);
    return player.r[0];
  }
}

/**
 * Create 10 classmates and 1 teacher for the player
 */
export function createClassmates(player: Player): void {
  // Create 10 classmates
  for (let i = 0; i < 10; i++) {
    createCharacter(player, 'random', 'similar', 'classmate');
  }

  // Create teacher
  const teacher = createCharacter(player, 'random', 'random_adults', 'teacher');
  teacher.job = { title: 'Teacher', income: 45000 };
}

/**
 * Create coworkers and a boss for the player
 */
export function createCoworkers(player: Player, occupation?: { title: string; income: number }): void {
  // Create 5-8 coworkers
  const numCoworkers = rand(5, 8);
  for (let i = 0; i < numCoworkers; i++) {
    const coworker = createCharacter(player, 'random', 'random_teens_adults', 'coworker');
    if (occupation) {
      coworker.job = occupation;
    }
  }

  // Create boss
  const boss = createCharacter(player, 'random', 'random_adults', 'boss');
  if (occupation) {
    boss.job = occupation;
  }
}

/**
 * Create classmates/teammates for an extracurricular activity
 * Called when player joins an activity to create social connections
 *
 * Creates 3-5 activity-specific classmates who share the activity
 * These NPCs will have the activity in their activities array
 */
export function createActivityClassmates(
  player: Player,
  activity: { id: string; title: string; type: string; energyModifier?: number }
): Person[] {
  const createdClassmates: Person[] = [];
  const numClassmates = rand(3, 5);

  for (let i = 0; i < numClassmates; i++) {
    // Create a classmate of similar age
    const classmate = createCharacter(player, 'random', 'similar', 'classmate');

    // Add the activity relationship
    classmate.relationships.push(`${activity.title.toLowerCase()}_teammate`);

    // Add activity to the classmate's activities so they share it
    classmate.activities = classmate.activities ?? [];
    classmate.activities.push(activity);

    // Create activity record for the classmate
    classmate.activityRecords = classmate.activityRecords ?? [];
    classmate.activityRecords.push({
      id: activity.id,
      type: activity.type,
      date: player.date,
      focus: 'Balanced',
    });

    // Set initial affinity based on sharing the activity
    classmate.affinity = rand(40, 70);

    // Update title to include activity context
    const activityTitle = activity.title;
    (classmate as unknown as { title: string }).title = `${activityTitle} Teammate`;

    createdClassmates.push(classmate);
  }

  return createdClassmates;
}

// ============================================================
// Character Lookup Functions
// ============================================================

/**
 * Get a person by their ID from player's relationships
 */
export function getPerson(player: Player, id: string): Person | null {
  return player.r.find((p) => p.id === id) ?? null;
}

/**
 * Get a person by their relationship type
 */
export function getRelationship(player: Player, type: string): Person | null {
  return player.r.find((p) => p.relationships.includes(type)) ?? null;
}

// ============================================================
// Relationship Management Functions
// ============================================================

/**
 * Update a relationship type for all matching characters
 */
export function updateRelationship(
  player: Player,
  oldRelationship: string,
  newRelationship: string,
  newTitle?: string
): Player {
  for (const person of player.r) {
    const index = person.relationships.indexOf(oldRelationship);
    if (index !== -1) {
      person.relationships.splice(index, 1);
      person.relationships.push(newRelationship);
      if (newTitle) {
        (person as unknown as { title: string }).title = newTitle;
      }
    }
  }
  return player;
}

/**
 * Update affinity between player and a person
 */
export function updatePersonAffinity(player: Player, person: Person, amount: number): void {
  person.affinity = Math.max(-100, Math.min(100, person.affinity + amount));
  // High-water mark for the "relationship at risk" neglect nudge (T010d).
  if (person.affinity >= 70) {
    person.affinityWasHigh = true;
  }
}

// ============================================================
// Character Setup Functions
// ============================================================

/**
 * Set up the main player character with initial family and relationships
 */
export function characterSetup(
  player: Player,
  data: { name?: string; age?: string; sex?: Sex }
): Player {
  // Set name
  if (data.name) {
    const nameParts = data.name.split(' ');
    player.c.firstname = nameParts[0];
    player.c.lastname = nameParts.length > 1 ? nameParts[1] : getLastname();
  }

  // Set age
  if (data.age) {
    player.c.ageYears = parseInt(data.age, 10);
  } else {
    player.c.ageYears = 15;
  }
  player.c.ageDays = player.c.ageYears * 365;

  // Set sex
  if (data.sex) {
    player.c.sex = data.sex;
  }
  player.c.affinity = 100;

  // Set avatar
  setAvatar(player.c);

  // Set default name if not provided
  if (!player.c.firstname) {
    player.c.firstname = getFirstname(player.c.sex);
  }
  if (!player.c.lastname) {
    player.c.lastname = getLastname();
  }

  // Add family
  addParents(player);
  addOlderSiblings(player);
  addGrandparents(player);

  // Set character values
  setValues(player, player.c);

  // Initialize habits based on age
  setHabits(player.c);

  // Set up education based on age (school enrollment)
  if (player.c.ageYears >= 5) {
    setEducation(player, player.c);
    // Create classmates if in school
    if (player.c.ageYears >= 5 && player.c.ageYears < 18) {
      createClassmates(player);
    }
  }

  // Activate player
  player.controller = 'active';

  // Add a significant other (boyfriend/girlfriend) if player is old enough.
  // Content safety: romantic relationships are adults only (18+).
  if (player.c.ageYears >= 18) {
    getPartner(player);
  }

  // Also add a same-sex friend
  addFriend(player, player.c.sex, 'similar');

  player.status = 'playing';

  return player;
}

// Export all functions
export const characterManager = {
  generatePersonDescription,
  generateOpenAIDescription,
  setBirthday,
  setValues,
  getPartner,
  addChild,
  getYoungestChild,
  getEldestLivingChild,
  addParents,
  addOlderSiblings,
  addGrandparents,
  addFriend,
  getRandomClassmate,
  getRandomFriend,
  getRandomCharacter,
  getRandomFamily,
  getAllFamily,
  createCharacter,
  createClassmates,
  createCoworkers,
  createActivityClassmates,
  getPerson,
  getRelationship,
  updateRelationship,
  updatePersonAffinity,
  characterSetup,
};
