"use client";

import { useEffect, useState } from "react";
import { ABILITIES, Ability, Skill, SKILL_ABILITY } from "@/types/content";
import type { AdvantageScope, Effect, EffectTarget } from "@/types/core";
import SpellProgressionTable from "./SpellProgressionTable";

/**
 * Comma-list input with a local string buffer so typing spaces and multi-word items
 * (like "thieves' tools") doesn't get eaten while typing.
 */
function CommaListInput({
  value,
  onCommit,
  placeholder,
  className,
}: {
  value: string[];
  onCommit: (next: string[]) => void;
  placeholder?: string;
  className?: string;
}) {
  const [buf, setBuf] = useState(value.join(", "));

  useEffect(() => {
    setBuf(value.join(", "));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value.join("\u0001")]);

  const commit = () => {
    const parsed = buf.split(",").map((s) => s.trim()).filter(Boolean);
    onCommit(parsed);
  };

  return (
    <input
      type="text"
      value={buf}
      onChange={(e) => setBuf(e.target.value)}
      onBlur={commit}
      placeholder={placeholder}
      className={className}
    />
  );
}

const SKILLS = Object.keys(SKILL_ABILITY) as Skill[];

const TARGET_KINDS: EffectTarget["kind"][] = [
  "ability",
  "abilityScoreChoice",
  "speed",
  "hpMax",
  "armorClass",
  "initiative",
  "savingThrowProficiency",
  "skillProficiency",
  "skillProficiencyChoice",
  "skillExpertise",
  "toolExpertise",
  "expertiseChoice",
  "armorProficiency",
  "weaponProficiency",
  "toolProficiency",
  "language",
  "resistance",
  "immunity",
  "vulnerability",
  "grantSpell",
  "grantSpellcasting",
  "grantFeat",
  "extraAttack",
  "grantSubclassChoice",
  "advantage",
  "disadvantage",
  "action",
  "bonusAction",
  "reaction",
  "custom",
];

const KIND_LABELS: Record<EffectTarget["kind"], string> = {
  ability: "Ability score",
  abilityScoreChoice: "Ability score improvement (choose)",
  speed: "Speed",
  hpMax: "HP Max",
  armorClass: "Armor class",
  initiative: "Initiative",
  savingThrowProficiency: "Saving throw prof.",
  skillProficiency: "Skill proficiency",
  skillProficiencyChoice: "Skill proficiency (choose N)",
  skillExpertise: "Skill expertise",
  toolExpertise: "Tool expertise",
  expertiseChoice: "Expertise (choose N)",
  armorProficiency: "Armor proficiency",
  weaponProficiency: "Weapon proficiency",
  toolProficiency: "Tool proficiency",
  language: "Language",
  resistance: "Damage resistance",
  immunity: "Damage immunity",
  vulnerability: "Damage vulnerability",
  grantSpell: "Grant spell",
  grantSpellcasting: "Grant spellcasting",
  grantFeat: "Grant feat",
  extraAttack: "Extra attack",
  grantSubclassChoice: "Grant subclass choice",
  advantage: "Advantage",
  disadvantage: "Disadvantage",
  action: "Action",
  bonusAction: "Bonus Action",
  reaction: "Reaction",
  custom: "Custom note",
};

const ADV_SCOPES = ["attack", "save", "skill", "check"] as const;
const SCOPE_LABELS: Record<(typeof ADV_SCOPES)[number], string> = {
  attack: "attack rolls",
  save: "saving throws",
  skill: "skill check",
  check: "ability checks",
};

function defaultTargetFor(kind: EffectTarget["kind"]): EffectTarget {
  switch (kind) {
    case "ability": return { kind, ability: "strength" };
    case "abilityScoreChoice": return { kind, points: 2, maxPerAbility: 2, cap: 20 };
    case "speed":
    case "hpMax":
    case "armorClass":
    case "initiative": return { kind };
    case "savingThrowProficiency": return { kind, ability: "strength" };
    case "skillProficiency":
    case "skillExpertise": return { kind, skill: "athletics" };
    case "skillProficiencyChoice": return { kind, count: 2, from: [] };
    case "toolExpertise": return { kind, tool: "" };
    case "expertiseChoice": return { kind, count: 2, skillPool: "characterSkills", toolPool: [] };
    case "armorProficiency":
    case "weaponProficiency":
    case "toolProficiency":
    case "language": return { kind, value: "" };
    case "resistance":
    case "immunity":
    case "vulnerability": return { kind, damageType: "fire" };
    case "grantSpell": return { kind, spellId: "" };
    case "grantSpellcasting": return {
      kind,
      ability: "intelligence",
      progression: [{ level: 1, cantripsKnown: 0, spellsKnown: 0, slots: [] }],
    };
    case "grantFeat": return { kind, featId: "" };
    case "extraAttack": return { kind, count: 1 };
    case "grantSubclassChoice": return { kind, label: "" };
    case "advantage":
    case "disadvantage": return { kind, scope: { on: "attack" }, condition: "" };
    case "action":
    case "bonusAction":
    case "reaction": return { kind, note: "" };
    case "custom": return { kind, note: "" };
  }
}

function defaultScope(on: AdvantageScope["on"]): AdvantageScope {
  switch (on) {
    case "attack": return { on };
    case "save": return { on, ability: undefined };
    case "skill": return { on, skill: "athletics" };
    case "check": return { on, ability: undefined };
  }
}

interface Props {
  effects: Effect[];
  onChange: (next: Effect[]) => void;
}

export default function EffectEditor({ effects, onChange }: Props) {
  const update = (idx: number, patch: Partial<Effect>) => {
    onChange(effects.map((e, i) => (i === idx ? { ...e, ...patch } : e)));
  };
  const updateTarget = (idx: number, target: EffectTarget) => update(idx, { target });
  const remove = (idx: number) => onChange(effects.filter((_, i) => i !== idx));
  const add = () =>
    onChange([...effects, { target: { kind: "ability", ability: "strength" }, operation: "increase", value: 1 }]);

  const needsValue = (kind: EffectTarget["kind"]) =>
    ["ability", "speed", "hpMax", "armorClass", "initiative"].includes(kind);

  return (
    <div className="space-y-3">
      {effects.length === 0 && (
        <p className="text-sm text-neutral-500 italic">No effects. Click below to add one.</p>
      )}
      {effects.map((eff, i) => {
        const kind = eff.target.kind;
        return (
          <div key={i} className="flex flex-wrap items-center gap-2 p-3 border border-neutral-700 rounded bg-neutral-950/50">
            <select
              className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
              value={kind}
              onChange={(e) => updateTarget(i, defaultTargetFor(e.target.value as EffectTarget["kind"]))}
            >
              {TARGET_KINDS.map((k) => (
                <option key={k} value={k}>{KIND_LABELS[k]}</option>
              ))}
            </select>

            {eff.target.kind === "ability" && (
              <select
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                value={eff.target.ability}
                onChange={(e) => updateTarget(i, { kind: "ability", ability: e.target.value as Ability })}
              >
                {ABILITIES.map((a) => <option key={a} value={a}>{a}</option>)}
              </select>
            )}
            {eff.target.kind === "abilityScoreChoice" && (() => {
              const t = eff.target;
              const setPatch = (patch: Partial<typeof t>) =>
                updateTarget(i, { ...t, ...patch } as EffectTarget);
              return (
                <div className="flex items-center gap-2">
                  <span className="text-xs text-neutral-500">distribute</span>
                  <input
                    type="number"
                    min={1}
                    value={t.points}
                    onChange={(e) => setPatch({ points: Math.max(1, Number(e.target.value) || 1) })}
                    className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-16"
                  />
                  <span className="text-xs text-neutral-500">points, max</span>
                  <input
                    type="number"
                    min={1}
                    value={t.maxPerAbility}
                    onChange={(e) => setPatch({ maxPerAbility: Math.max(1, Number(e.target.value) || 1) })}
                    className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-16"
                  />
                  <span className="text-xs text-neutral-500">per ability, cap</span>
                  <input
                    type="number"
                    min={1}
                    placeholder="none"
                    value={t.cap ?? ""}
                    onChange={(e) =>
                      setPatch({ cap: e.target.value ? Math.max(1, Number(e.target.value)) : undefined })
                    }
                    className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-16"
                  />
                </div>
              );
            })()}
            {eff.target.kind === "savingThrowProficiency" && (
              <select
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                value={eff.target.ability}
                onChange={(e) => updateTarget(i, { kind: "savingThrowProficiency", ability: e.target.value as Ability })}
              >
                {ABILITIES.map((a) => <option key={a} value={a}>{a}</option>)}
              </select>
            )}
            {(eff.target.kind === "skillProficiency" || eff.target.kind === "skillExpertise") && (
              <select
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                value={eff.target.skill}
                onChange={(e) => updateTarget(i, { kind: eff.target.kind as "skillProficiency" | "skillExpertise", skill: e.target.value as Skill })}
              >
                {SKILLS.map((s) => <option key={s} value={s}>{s}</option>)}
              </select>
            )}
            {eff.target.kind === "toolExpertise" && (
              <input
                type="text"
                placeholder="tool name (e.g. thieves' tools)"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-56"
                value={eff.target.tool}
                onChange={(e) => updateTarget(i, { kind: "toolExpertise", tool: e.target.value })}
              />
            )}
            {eff.target.kind === "expertiseChoice" && (() => {
              const t = eff.target;
              const setPatch = (patch: Partial<typeof t>) =>
                updateTarget(i, { ...t, ...patch } as EffectTarget);
              const skillPoolMode = t.skillPool === "characterSkills" ? "characterSkills" : "specific";
              return (
                <div className="flex flex-col gap-2 w-full">
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-neutral-500">choose</span>
                    <input
                      type="number"
                      min={1}
                      value={t.count}
                      onChange={(e) => setPatch({ count: Math.max(1, Number(e.target.value) || 1) })}
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-16"
                    />
                    <span className="text-xs text-neutral-500">total from:</span>
                  </div>
                  <div className="flex items-center gap-2 flex-wrap">
                    <span className="text-xs text-neutral-400">Skill pool:</span>
                    <select
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                      value={skillPoolMode}
                      onChange={(e) =>
                        setPatch({
                          skillPool: e.target.value === "characterSkills" ? "characterSkills" : [],
                        })
                      }
                    >
                      <option value="characterSkills">Any skill character is proficient in</option>
                      <option value="specific">Specific skills</option>
                    </select>
                  </div>
                  {Array.isArray(t.skillPool) && (
                    <div className="flex flex-wrap gap-1">
                      {SKILLS.map((s) => {
                        const arr = t.skillPool as Skill[];
                        const on = arr.includes(s);
                        return (
                          <label
                            key={s}
                            className={`px-2 py-0.5 text-xs rounded border cursor-pointer ${on ? "bg-amber-600/20 border-amber-500" : "border-neutral-700"}`}
                          >
                            <input
                              type="checkbox"
                              className="hidden"
                              checked={on}
                              onChange={() =>
                                setPatch({
                                  skillPool: on ? arr.filter((x) => x !== s) : [...arr, s],
                                })
                              }
                            />
                            {s}
                          </label>
                        );
                      })}
                    </div>
                  )}
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-neutral-400">Also eligible tools (comma):</span>
                    <CommaListInput
                      value={t.toolPool}
                      onCommit={(next) => setPatch({ toolPool: next })}
                      placeholder="thieves' tools"
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 flex-1"
                    />
                  </div>
                </div>
              );
            })()}
            {eff.target.kind === "skillProficiencyChoice" && (() => {
              const t = eff.target;
              const setCount = (n: number) =>
                updateTarget(i, { kind: "skillProficiencyChoice", count: n, from: t.from });
              const toggleFrom = (s: Skill) => {
                const next = t.from.includes(s) ? t.from.filter((x) => x !== s) : [...t.from, s];
                updateTarget(i, { kind: "skillProficiencyChoice", count: t.count, from: next });
              };
              return (
                <div className="flex flex-col gap-2 w-full">
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-neutral-500">choose</span>
                    <input
                      type="number"
                      min={1}
                      max={t.from.length || 18}
                      value={t.count}
                      onChange={(e) => setCount(Math.max(1, Number(e.target.value) || 1))}
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-16"
                    />
                    <span className="text-xs text-neutral-500">of {t.from.length} option(s)</span>
                  </div>
                  <div className="flex flex-wrap gap-1">
                    {SKILLS.map((s) => {
                      const on = t.from.includes(s);
                      return (
                        <label
                          key={s}
                          className={`px-2 py-0.5 text-xs rounded border cursor-pointer ${on ? "bg-amber-600/20 border-amber-500" : "border-neutral-700"}`}
                        >
                          <input type="checkbox" className="hidden" checked={on} onChange={() => toggleFrom(s)} />
                          {s}
                        </label>
                      );
                    })}
                  </div>
                </div>
              );
            })()}
            {(eff.target.kind === "armorProficiency" ||
              eff.target.kind === "weaponProficiency" ||
              eff.target.kind === "toolProficiency" ||
              eff.target.kind === "language") && (
              <input
                type="text"
                placeholder="value"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-40"
                value={eff.target.value}
                onChange={(e) => updateTarget(i, { kind: eff.target.kind as "armorProficiency" | "weaponProficiency" | "toolProficiency" | "language", value: e.target.value })}
              />
            )}
            {(eff.target.kind === "resistance" ||
              eff.target.kind === "immunity" ||
              eff.target.kind === "vulnerability") && (
              <input
                type="text"
                placeholder="damage type"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-32"
                value={eff.target.damageType}
                onChange={(e) => updateTarget(i, { kind: eff.target.kind as "resistance" | "immunity" | "vulnerability", damageType: e.target.value })}
              />
            )}
            {eff.target.kind === "grantSpell" && (
              <input
                type="text"
                placeholder="spell id"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-40"
                value={eff.target.spellId}
                onChange={(e) => updateTarget(i, { kind: "grantSpell", spellId: e.target.value })}
              />
            )}
            {eff.target.kind === "grantSpellcasting" && (() => {
              const t = eff.target;
              const setPatch = (patch: Partial<typeof t>) =>
                updateTarget(i, { ...t, ...patch } as EffectTarget);
              return (
                <div className="flex flex-col gap-2 w-full">
                  <div className="flex items-center gap-2">
                    <span className="text-xs text-neutral-500">Ability:</span>
                    <select
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                      value={t.ability}
                      onChange={(e) => setPatch({ ability: e.target.value as Ability })}
                    >
                      {ABILITIES.map((a) => <option key={a} value={a}>{a}</option>)}
                    </select>
                    <label className="text-xs text-neutral-500 flex items-center gap-1">
                      <input
                        type="checkbox"
                        checked={t.ritual === true}
                        onChange={(e) => setPatch({ ritual: e.target.checked })}
                      />
                      Ritual casting
                    </label>
                  </div>
                  <SpellProgressionTable
                    progression={t.progression}
                    onChange={(rows) => setPatch({ progression: rows })}
                  />
                </div>
              );
            })()}
            {eff.target.kind === "grantFeat" && (
              <input
                type="text"
                placeholder="feat id"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-40"
                value={eff.target.featId}
                onChange={(e) => updateTarget(i, { kind: "grantFeat", featId: e.target.value })}
              />
            )}
            {eff.target.kind === "grantSubclassChoice" && (
              <input
                type="text"
                placeholder="label (e.g. Roguish Archetype)"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 flex-1"
                value={eff.target.label ?? ""}
                onChange={(e) => updateTarget(i, { kind: "grantSubclassChoice", label: e.target.value })}
              />
            )}
            {eff.target.kind === "extraAttack" && (
              <input
                type="number"
                min={1}
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-20"
                value={eff.target.count}
                onChange={(e) => updateTarget(i, { kind: "extraAttack", count: Number(e.target.value) || 1 })}
              />
            )}
            {(eff.target.kind === "advantage" || eff.target.kind === "disadvantage") && (() => {
              const kindLocal = eff.target.kind;
              const scope = eff.target.scope;
              const cond = eff.target.condition ?? "";
              const setScope = (next: AdvantageScope) =>
                updateTarget(i, { kind: kindLocal, scope: next, condition: cond });
              const setCond = (c: string) =>
                updateTarget(i, { kind: kindLocal, scope, condition: c });
              return (
                <>
                  <span className="text-xs text-neutral-500">on</span>
                  <select
                    className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                    value={scope.on}
                    onChange={(e) => setScope(defaultScope(e.target.value as AdvantageScope["on"]))}
                  >
                    {ADV_SCOPES.map((s) => <option key={s} value={s}>{SCOPE_LABELS[s]}</option>)}
                  </select>
                  {scope.on === "skill" && (
                    <select
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                      value={scope.skill}
                      onChange={(e) => setScope({ on: "skill", skill: e.target.value as Skill })}
                    >
                      {SKILLS.map((s) => <option key={s} value={s}>{s}</option>)}
                    </select>
                  )}
                  {(scope.on === "save" || scope.on === "check") && (
                    <select
                      className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                      value={scope.ability ?? ""}
                      onChange={(e) => {
                        const val = e.target.value;
                        setScope({ on: scope.on, ability: val ? (val as Ability) : undefined } as AdvantageScope);
                      }}
                    >
                      <option value="">all</option>
                      {ABILITIES.map((a) => <option key={a} value={a}>{a}</option>)}
                    </select>
                  )}
                  <input
                    type="text"
                    placeholder="condition (optional, e.g. 'vs poison')"
                    className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 flex-1 min-w-[10rem]"
                    value={cond}
                    onChange={(e) => setCond(e.target.value)}
                  />
                </>
              );
            })()}
            {(eff.target.kind === "action" || eff.target.kind === "bonusAction" || eff.target.kind === "reaction") && (
              <input
                type="text"
                placeholder="note (e.g. 'Dash, Disengage, or Hide')"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 flex-1"
                value={eff.target.note}
                onChange={(e) => updateTarget(i, { kind: eff.target.kind as "action" | "bonusAction" | "reaction", note: e.target.value })}
              />
            )}
            {eff.target.kind === "custom" && (
              <input
                type="text"
                placeholder="note"
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 flex-1"
                value={eff.target.note}
                onChange={(e) => updateTarget(i, { kind: "custom", note: e.target.value })}
              />
            )}

            {needsValue(kind) && (
              <>
                <select
                  className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700"
                  value={eff.operation}
                  onChange={(e) => update(i, { operation: e.target.value as Effect["operation"] })}
                >
                  <option value="increase">+</option>
                  <option value="decrease">−</option>
                  <option value="set">=</option>
                </select>
                <input
                  type="number"
                  className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-20"
                  value={eff.value ?? 0}
                  onChange={(e) => update(i, { value: Number(e.target.value) })}
                />
              </>
            )}

            <div className="ml-auto flex items-center gap-1">
              <label className="text-[10px] text-neutral-500 uppercase">Lv</label>
              <input
                type="number"
                min={1}
                max={20}
                placeholder="1"
                value={eff.level ?? ""}
                onChange={(e) => update(i, { level: e.target.value ? Number(e.target.value) : undefined })}
                className="bg-neutral-800 text-sm rounded px-2 py-1 border border-neutral-700 w-14 text-center"
                title="Minimum level for this effect to apply"
              />
              <button
                onClick={() => remove(i)}
                className="text-red-400 hover:text-red-300 text-sm px-2"
                type="button"
              >
                Remove
              </button>
            </div>
          </div>
        );
      })}
      <button
        onClick={add}
        type="button"
        className="text-sm text-amber-400 border border-amber-400/40 hover:bg-amber-400/10 rounded px-3 py-1"
      >
        + Add effect
      </button>
    </div>
  );
}
