import { useState } from 'react';
import { Sparkles, BrainCircuit, X, Minus, Plus } from 'lucide-react';
import { newId } from '@/lib/ids';
import { getSystem } from '@/lib/rules';
import type { AbilityKey, CharacterRulesInput, ProficiencyRank } from '@/lib/rules';
import { type SpellEntry, newSpellEntry } from '@/lib/schemas';
import { castSpell, availableSlotLevels, dropConcentration } from '@/lib/mechanics';
import { multiclassSlots } from '@/lib/rules/dnd5e/progression';
import { formatModifier } from '@/lib/format';
import { Button } from '@/components/ui/Button';
import { Input, Select } from '@/components/ui/Input';
import { NumberField } from '@/components/ui/NumberField';
import { SheetSection, type SectionProps } from './common';

const CASTING_ABILITIES: { key: AbilityKey; label: string }[] = [
  { key: 'int', label: 'Intelligence' },
  { key: 'wis', label: 'Wisdom' },
  { key: 'cha', label: 'Charisma' },
];

export function SpellcastingSection({ c, update }: SectionProps) {
  const [spellName, setSpellName] = useState('');
  const [spellLevel, setSpellLevel] = useState(0);
  const sys = getSystem(c.system);
  const sc = c.spellcasting;

  const ability = c.spellcastingAbility;
  const rulesInput: CharacterRulesInput = {
    level: c.level,
    abilities: c.abilities,
    ...(c.spellcastingRank ? { spellcastingRank: c.spellcastingRank as ProficiencyRank } : {}),
  };
  const dc = ability ? sys.spellSaveDc?.(rulesInput, ability) : undefined;
  const atk = ability ? sys.spellAttackBonus(rulesInput, ability) : undefined;

  const setSlots = (slots: typeof sc.slots) => update({ spellcasting: { ...sc, slots } });
  const patchSlot = (level: number, p: Partial<(typeof sc.slots)[number]>) =>
    setSlots(sc.slots.map((s) => (s.level === level ? { ...s, ...p } : s)));
  // pf2e has 10 spell ranks; 5e tops out at 9.
  const maxRank = c.system === 'pf2e' ? 10 : 9;
  const addSlotLevel = () => {
    const next = (sc.slots.at(-1)?.level ?? 0) + 1;
    if (next > maxRank) return;
    setSlots([...sc.slots, { level: next, max: 1, current: 1 }]);
  };

  const addSpell = () => {
    if (spellName.trim() === '') return;
    const entry: SpellEntry = newSpellEntry({ id: newId(), name: spellName.trim(), level: spellLevel });
    update({ spellcasting: { ...sc, spells: [...sc.spells, entry] } });
    setSpellName('');
  };
  const patchSpell = (id: string, p: Partial<SpellEntry>) =>
    update({ spellcasting: { ...sc, spells: sc.spells.map((s) => (s.id === id ? { ...s, ...p } : s)) } });
  const removeSpell = (id: string) =>
    update({ spellcasting: { ...sc, spells: sc.spells.filter((s) => s.id !== id) } });

  // Casting a spell enforces slot consumption + concentration via the kernel.
  const [castMsg, setCastMsg] = useState<{ text: string; ok: boolean } | null>(null);
  // Chosen slot level per spell (for warlock pact slots / upcasting); defaults to lowest.
  const [castLevel, setCastLevel] = useState<Record<string, number>>({});
  const cast = (id: string, atLevel?: number) => {
    const res = castSpell(c, id, atLevel);
    if (res.ok) {
      update(res.patch);
      setCastMsg({ text: res.log.join(' '), ok: true });
    } else {
      setCastMsg({ text: res.reason, ok: false });
    }
  };

  const spellsByLevel = [...sc.spells].sort((a, b) => a.level - b.level || a.name.localeCompare(b.name));

  return (
    <SheetSection title="Spellcasting">
      <div className="mb-3 flex flex-wrap items-center gap-3">
        <label className="text-xs text-muted">
          Casting ability
          <Select
            className="ml-2 w-auto"
            value={ability ?? ''}
            onChange={(e) => update({ spellcastingAbility: (e.target.value || undefined) as typeof c.spellcastingAbility })}
          >
            <option value="">None</option>
            {CASTING_ABILITIES.map((a) => (
              <option key={a.key} value={a.key}>{a.label}</option>
            ))}
          </Select>
        </label>
        {/* pf2e: spell DC/attack scale with spellcasting proficiency (expert/master/legendary). */}
        {c.system === 'pf2e' && ability && (
          <label className="text-xs text-muted">
            Proficiency
            <Select
              className="ml-2 w-auto"
              value={c.spellcastingRank ?? 'trained'}
              onChange={(e) => update({ spellcastingRank: e.target.value as ProficiencyRank })}
            >
              {(['trained', 'expert', 'master', 'legendary'] as const).map((r) => (
                <option key={r} value={r}>{r[0]!.toUpperCase() + r.slice(1)}</option>
              ))}
            </Select>
          </label>
        )}
        {ability && (
          <div className="flex gap-4 text-sm">
            <span className="text-muted">Spell DC <span className="font-display text-lg font-semibold text-accent">{dc}</span></span>
            <span className="text-muted">Attack <span className="font-display text-lg font-semibold text-accent">{atk !== undefined ? formatModifier(atk) : '—'}</span></span>
          </div>
        )}
      </div>

      {/* Concentration banner — enforced: one spell at a time. */}
      {c.concentration && (
        <div className="mb-3 flex items-center gap-2 rounded-md border border-accent/40 bg-accent/5 px-3 py-1.5 text-sm">
          <BrainCircuit size={15} className="shrink-0 text-accent" aria-hidden />
          <span className="text-ink">Concentrating on <span className="font-medium">{c.concentration.spellName}</span></span>
          <Button size="sm" variant="ghost" className="ml-auto" onClick={() => update(dropConcentration(c))}>Drop</Button>
        </div>
      )}
      {castMsg && (
        <p className={`mb-3 text-xs ${castMsg.ok ? 'text-success' : 'text-danger'}`} aria-live="polite">{castMsg.text}</p>
      )}

      {/* Spell slots */}
      <div className="mb-4">
        <div className="mb-1 flex items-center gap-2">
          <span className="smallcaps">Spell slots</span>
          <Button size="sm" variant="ghost" onClick={addSlotLevel}>+ slot level</Button>
        </div>
        {sc.slots.length === 0 ? (
          <p className="text-sm text-muted">No spell slots configured.</p>
        ) : (
          <div className="flex flex-wrap gap-2">
            {sc.slots.map((s) => (
              <div key={s.level} className="rounded-md border border-line bg-panel px-2 py-1 text-center">
                <div className="text-[10px] uppercase text-muted">Lv {s.level}</div>
                <div className="flex items-center gap-1">
                  <Button size="icon" variant="ghost" className="h-6 w-6" onClick={() => patchSlot(s.level, { current: Math.max(0, s.current - 1) })} aria-label={`Spend level ${s.level} slot`}><Minus size={14} aria-hidden /></Button>
                  <span className="text-sm"><span className="font-medium text-ink">{s.current}</span>/<NumberField className="inline-block w-12" value={s.max} min={0} onChange={(v) => patchSlot(s.level, { max: v, current: Math.min(v, s.current) })} aria-label={`Level ${s.level} max slots`} /></span>
                  <Button size="icon" variant="ghost" className="h-6 w-6" onClick={() => patchSlot(s.level, { current: Math.min(s.max, s.current + 1) })} aria-label={`Regain level ${s.level} slot`}><Plus size={14} aria-hidden /></Button>
                </div>
              </div>
            ))}
          </div>
        )}
        {c.system === '5e' && <MulticlassSlots onApply={setSlots} />}
      </div>

      {/* Spell list */}
      <div className="mb-2 flex items-end gap-2">
        <label className="flex-1 min-w-40 text-xs text-muted">
          Add spell
          <Input value={spellName} onChange={(e) => setSpellName(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addSpell()} placeholder="Fireball" />
        </label>
        <label className="text-xs text-muted">
          Level
          <Select className="w-20" value={spellLevel} onChange={(e) => setSpellLevel(Number(e.target.value))}>
            <option value={0}>Cantrip</option>
            {Array.from({ length: maxRank }, (_, i) => i + 1).map((l) => (
              <option key={l} value={l}>{l}</option>
            ))}
          </Select>
        </label>
        <Button variant="primary" onClick={addSpell}>Add</Button>
      </div>
      {spellsByLevel.length === 0 ? (
        <p className="text-sm text-muted">No spells added.</p>
      ) : (
        <ul className="space-y-1">
          {spellsByLevel.map((s) => (
            <li key={s.id} className="flex items-center gap-2 rounded-md border border-line bg-panel px-3 py-1.5 text-sm">
              <span className="w-16 text-xs text-muted">{s.level === 0 ? 'Cantrip' : `Lv ${s.level}`}</span>
              <span className="flex-1 text-ink">
                {s.name}
                {s.concentration && <BrainCircuit size={12} className="ml-1 inline text-accent" aria-label="Concentration" />}
              </span>
              {s.level > 0 && (
                <label className="flex items-center gap-1 text-xs text-muted">
                  <input type="checkbox" checked={s.prepared} onChange={(e) => patchSpell(s.id, { prepared: e.target.checked })} />
                  Prepared
                </label>
              )}
              {s.level === 0 ? (
                <Button size="sm" variant="ghost" onClick={() => cast(s.id)} aria-label={`Cast ${s.name}`}>
                  <Sparkles size={13} aria-hidden /> Cast
                </Button>
              ) : (() => {
                const levels = availableSlotLevels(sc, s.level);
                if (levels.length === 0) return <span className="text-xs text-muted" title="No available slot">no slots</span>;
                const chosen = castLevel[s.id] && levels.includes(castLevel[s.id]!) ? castLevel[s.id]! : levels[0]!;
                return (
                  <div className="flex items-center gap-1">
                    {levels.length > 1 && (
                      <Select className="w-auto py-0.5 text-xs" value={chosen} aria-label={`Slot level for ${s.name}`}
                        onChange={(e) => setCastLevel((p) => ({ ...p, [s.id]: Number(e.target.value) }))}>
                        {levels.map((l) => <option key={l} value={l}>{`L${l}`}</option>)}
                      </Select>
                    )}
                    <Button size="sm" variant="ghost" onClick={() => cast(s.id, chosen)} aria-label={`Cast ${s.name} at level ${chosen}`}>
                      <Sparkles size={13} aria-hidden /> Cast{chosen !== s.level ? ` L${chosen}` : ''}
                    </Button>
                  </div>
                );
              })()}
              <Button size="icon" variant="ghost" className="text-danger" onClick={() => removeSpell(s.id)} aria-label={`Remove ${s.name}`}><X size={14} aria-hidden /></Button>
            </li>
          ))}
        </ul>
      )}
    </SheetSection>
  );
}

/** PHB multiclass spell-slot calculator: enter your class levels by caster type
 *  and it fills the slot table correctly (full ×1, half ÷2, third ÷3). */
function MulticlassSlots({ onApply }: { onApply: (slots: { level: number; max: number; current: number }[]) => void }) {
  const [full, setFull] = useState(0);
  const [half, setHalf] = useState(0);
  const [third, setThird] = useState(0);
  return (
    <details className="mt-2">
      <summary className="cursor-pointer text-xs text-muted hover:text-ink">Multiclass slot calculator</summary>
      <div className="mt-2 flex flex-wrap items-end gap-2 rounded-md border border-line bg-panel-2 p-2 text-xs text-muted">
        <label>Full-caster lvls<NumberField className="ml-1 w-14" value={full} min={0} max={20} onChange={setFull} aria-label="Full caster levels" /></label>
        <label>Half-caster lvls<NumberField className="ml-1 w-14" value={half} min={0} max={20} onChange={setHalf} aria-label="Half caster levels" /></label>
        <label>Third-caster lvls<NumberField className="ml-1 w-14" value={third} min={0} max={20} onChange={setThird} aria-label="Third caster levels" /></label>
        <Button size="sm" variant="secondary" onClick={() => onApply(multiclassSlots({ full, half, third }))}>Apply slots</Button>
        <span className="w-full text-[11px] text-faint">Bard/Cleric/Druid/Sorcerer/Wizard = full; Paladin/Ranger = half; Eldritch Knight/Arcane Trickster = third. Warlock pact slots are separate.</span>
      </div>
    </details>
  );
}
