import type { AbilityKey, AbilityScores } from '../types';

/**
 * PF2e ability scores are built from boosts, not a 5e-style array. Every score
 * starts at 10; an ancestry flaw subtracts 2; each boost adds +2 while the score
 * is below 18, otherwise +1. Boosts are applied in canonical order (ancestry →
 * background → class → free) so the rare >18 case resolves correctly.
 */

const ABIL_WORD: Record<string, AbilityKey> = {
  strength: 'str', dexterity: 'dex', constitution: 'con',
  intelligence: 'int', wisdom: 'wis', charisma: 'cha',
};

const NUM_WORD: Record<string, number> = { one: 1, two: 2, three: 3, four: 4 };

export function abilityWord(word: string): AbilityKey | undefined {
  return ABIL_WORD[word.trim().toLowerCase()];
}

function base10(): AbilityScores {
  return { str: 10, dex: 10, con: 10, int: 10, wis: 10, cha: 10 };
}

/** Apply an ordered list of boosts (and an optional flaw) to a base-10 spread. */
export function pf2eApplyBoosts(boosts: readonly AbilityKey[], flaw?: AbilityKey | null): AbilityScores {
  const s = base10();
  if (flaw) s[flaw] -= 2;
  for (const b of boosts) s[b] += s[b] < 18 ? 2 : 1;
  return s;
}

/**
 * Parse an ancestry `attribute` array into the fixed boosts and the number of free
 * boosts it grants. Handles specific abilities ("Constitution"), the "Free" token,
 * and prose like "Two free ability boosts".
 */
export function parseAncestryBoosts(attribute: unknown): { fixed: AbilityKey[]; free: number } {
  const arr = Array.isArray(attribute) ? attribute.map(String) : [];
  const fixed: AbilityKey[] = [];
  let free = 0;
  for (const raw of arr) {
    const k = abilityWord(raw);
    if (k) { fixed.push(k); continue; }
    const m = /(\bone\b|\btwo\b|\bthree\b|\bfour\b|\d+)\s+free/i.exec(raw);
    if (m) {
      const word = m[1]!.toLowerCase();
      const n = NUM_WORD[word] ?? Number(word);
      free += Number.isFinite(n) ? n : 1;
    } else if (/free/i.test(raw)) free += 1;
  }
  return { fixed, free };
}

/** Parse an ancestry flaw field (legacy ancestries) into a single ability, if any. */
export function parseFlaw(flaw: unknown): AbilityKey | undefined {
  if (Array.isArray(flaw)) { for (const f of flaw) { const k = abilityWord(String(f)); if (k) return k; } return undefined; }
  if (typeof flaw === 'string') return abilityWord(flaw);
  return undefined;
}

/**
 * Parse a background `attribute` array. A PF2e background grants one boost chosen
 * from its listed abilities plus one free boost; the data lists the choose-from
 * options. Returns the options and the free-boost count (1).
 */
export function parseBackgroundBoosts(attribute: unknown): { options: AbilityKey[]; free: number } {
  const arr = Array.isArray(attribute) ? attribute.map(String) : [];
  const options = arr.map(abilityWord).filter((k): k is AbilityKey => !!k);
  return { options, free: options.length ? 1 : 0 };
}
