import { useMemo, useState } from 'react';
import type { Campaign, Character } from '@/lib/schemas';
import {
  abilityModifier, getSystem, ABILITY_ABBR, type AbilityKey, type ProficiencyRank,
  planLevelUp, applyIncreases, bumpRank, getClassDef,
} from '@/lib/rules';
import { rollDice } from '@/lib/dice/notation';
import { createRng } from '@/lib/rng';
import { Modal } from '@/components/ui/Modal';
import { Button } from '@/components/ui/Button';
import { Select } from '@/components/ui/Input';
import { LevelUpAdvisor } from './LevelUpAdvisor';

const ABILITIES: AbilityKey[] = ['str', 'dex', 'con', 'int', 'wis', 'cha'];

export function LevelUpModal({ character, onApply, onClose }: {
  character: Character;
  onApply: (patch: Partial<Character>) => void;
  onClose: () => void;
}) {
  const conMod = abilityModifier(character.abilities.con);
  const plan = useMemo(
    () => planLevelUp(character.system, character.className, character.level, conMod),
    [character.system, character.className, character.level, conMod],
  );
  const sys = getSystem(character.system);
  const def = getClassDef(character.system, character.className);

  const [hpMethod, setHpMethod] = useState<'average' | 'roll'>('average');
  const asi = plan.choices.find((c) => c.kind === 'asi');
  const boosts = plan.choices.find((c) => c.kind === 'boosts');
  const skillInc = plan.choices.find((c) => c.kind === 'skill-increase');

  // ASI (5e): two +1 picks (same twice = +2) or take a feat instead.
  const keyDefaults = def?.keyAbilities ?? ['str', 'dex'];
  const [asiMode, setAsiMode] = useState<'asi' | 'feat'>('asi');
  const [asiPicks, setAsiPicks] = useState<AbilityKey[]>([keyDefaults[0] ?? 'str', keyDefaults[1] ?? keyDefaults[0] ?? 'con']);
  // Boosts (pf2e): four distinct picks.
  const [boostPicks, setBoostPicks] = useState<AbilityKey[]>(['str', 'dex', 'con', 'wis']);
  // Skill increase (pf2e): one skill to bump.
  const [skillKey, setSkillKey] = useState<string>(sys.skills[0]?.key ?? '');

  const atMax = character.level >= 20;
  const apply = () => {
    const gain = character.system === 'pf2e'
      ? plan.hpGainAverage
      : hpMethod === 'average' ? plan.hpGainAverage : Math.max(1, rollDice(`1d${plan.hitDie}`, createRng()).total + conMod);

    let abilities = character.abilities;
    if (asi && asiMode === 'asi') abilities = applyIncreases(abilities, asiPicks, '5e');
    if (boosts) abilities = applyIncreases(abilities, boostPicks, 'pf2e');

    const patch: Partial<Character> = {
      level: plan.nextLevel,
      hp: { ...character.hp, max: character.hp.max + gain, current: character.hp.current + gain },
      abilities,
    };
    if (plan.slots) {
      patch.spellcasting = { ...character.spellcasting, slots: plan.slots, ...(plan.pact ? { pact: plan.pact } : {}) };
    }
    if (skillInc && skillKey) {
      const current = (character.skillRanks[skillKey] as ProficiencyRank) ?? 'untrained';
      patch.skillRanks = { ...character.skillRanks, [skillKey]: bumpRank(current) };
    }
    onApply(patch);
    onClose();
  };

  const hpPreview = character.system === 'pf2e'
    ? `+${plan.hpGainAverage}`
    : hpMethod === 'average' ? `+${plan.hpGainAverage}` : `1d${plan.hitDie} ${conMod >= 0 ? '+' : ''}${conMod}`;

  return (
    <Modal
      open
      onClose={onClose}
      title={`Level up to ${plan.nextLevel}`}
      className="max-w-xl"
      footer={
        <>
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button variant="primary" disabled={atMax} onClick={apply}>Apply level {plan.nextLevel}</Button>
        </>
      }
    >
      {atMax ? (
        <p className="text-sm text-warning">Already at level 20.</p>
      ) : (
        <div className="space-y-4">
          {/* HP */}
          <section>
            <h3 className="mb-1 smallcaps">Hit points</h3>
            {character.system === '5e' ? (
              <div className="flex items-center gap-2">
                <Select value={hpMethod} onChange={(e) => setHpMethod(e.target.value as 'average' | 'roll')} className="w-44" aria-label="HP method">
                  <option value="average">Average (+{plan.hpGainAverage})</option>
                  <option value="roll">Roll d{plan.hitDie}</option>
                </Select>
                <span className="text-sm text-muted">Gain: <span className="font-medium text-ink">{hpPreview}</span> (CON {conMod >= 0 ? '+' : ''}{conMod})</span>
              </div>
            ) : (
              <p className="text-sm text-muted">Gain: <span className="font-medium text-ink">{hpPreview}</span> (class {plan.hitDie} + CON {conMod >= 0 ? '+' : ''}{conMod})</p>
            )}
          </section>

          {plan.notes.map((n) => <p key={n} className="text-sm text-muted">• {n}</p>)}

          {/* ASI (5e) */}
          {asi && (
            <section>
              <h3 className="mb-1 smallcaps">Ability Score Improvement</h3>
              <div className="mb-2 flex gap-1">
                {(['asi', 'feat'] as const).map((m) => (
                  <button key={m} onClick={() => setAsiMode(m)} className={`rounded-md px-3 py-1 text-sm ${asiMode === m ? 'bg-accent text-accent-ink' : 'bg-elevated text-muted hover:text-ink'}`}>
                    {m === 'asi' ? '+2 abilities' : 'Take a feat'}
                  </button>
                ))}
              </div>
              {asiMode === 'asi' ? (
                <div className="flex gap-2">
                  {[0, 1].map((i) => (
                    <Select key={i} aria-label={`ASI ability ${i + 1}`} value={asiPicks[i]} onChange={(e) => setAsiPicks((p) => p.map((v, j) => (j === i ? e.target.value as AbilityKey : v)))}>
                      {ABILITIES.map((a) => <option key={a} value={a}>{ABILITY_ABBR[a]} (+1)</option>)}
                    </Select>
                  ))}
                  <span className="self-center text-xs text-muted">pick the same twice for +2</span>
                </div>
              ) : (
                <p className="text-sm text-muted">Add your chosen feat on the sheet after leveling.</p>
              )}
            </section>
          )}

          {/* Boosts (pf2e) */}
          {boosts && (
            <section>
              <h3 className="mb-1 smallcaps">Ability boosts (choose 4)</h3>
              <div className="grid grid-cols-2 gap-2 sm:grid-cols-4">
                {[0, 1, 2, 3].map((i) => (
                  <Select key={i} aria-label={`Boost ${i + 1}`} value={boostPicks[i]} onChange={(e) => setBoostPicks((p) => p.map((v, j) => (j === i ? e.target.value as AbilityKey : v)))}>
                    {ABILITIES.map((a) => <option key={a} value={a} disabled={boostPicks.includes(a) && boostPicks[i] !== a}>{ABILITY_ABBR[a]}</option>)}
                  </Select>
                ))}
              </div>
            </section>
          )}

          {/* Skill increase (pf2e) */}
          {skillInc && (
            <section>
              <h3 className="mb-1 smallcaps">Skill increase</h3>
              <Select value={skillKey} onChange={(e) => setSkillKey(e.target.value)} aria-label="Skill to increase">
                {sys.skills.map((s) => {
                  const cur = (character.skillRanks[s.key] as ProficiencyRank) ?? 'untrained';
                  return <option key={s.key} value={s.key}>{s.label}: {cur} → {bumpRank(cur)}</option>;
                })}
              </Select>
            </section>
          )}

          {plan.choices.filter((c) => c.kind === 'feat').map((c) => (
            <p key={c.label} className="text-sm text-muted">• {c.label}</p>
          ))}

          {/* Strategic build-route advice */}
          <LevelUpAdvisor campaign={{ id: character.campaignId, name: '', system: character.system, description: '', createdAt: '', updatedAt: '' } as Campaign} character={character} />
        </div>
      )}
    </Modal>
  );
}
