"use client";

import { useMemo, useState } from "react";
import { ABILITIES, Ability, AbilityScores } from "@/types/content";
import { useCreator, AbilityMethod } from "../CreatorContext";
import { useDiceContext } from "@/components/DiceContext";
import { getAbilityModifier } from "@/lib/dndHelpers";

const STANDARD_ARRAY = [15, 14, 13, 12, 10, 8];
const POINT_BUY_COST: Record<number, number> = {
  8: 0, 9: 1, 10: 2, 11: 3, 12: 4, 13: 5, 14: 7, 15: 9,
};
const POINT_BUY_BUDGET = 27;

function fmtMod(m: number) { return m >= 0 ? `+${m}` : `${m}`; }

export default function AbilitiesStep() {
  const { draft, update, species, classes, backgrounds, features, subclasses } = useCreator();
  const dice = useDiceContext();

  const setMethod = (m: AbilityMethod) => {
    if (m === "standardArray") {
      update({ abilityMethod: m, abilities: { strength: 8, dexterity: 8, constitution: 8, intelligence: 8, wisdom: 8, charisma: 8 } });
    } else if (m === "pointBuy") {
      update({ abilityMethod: m, abilities: { strength: 8, dexterity: 8, constitution: 8, intelligence: 8, wisdom: 8, charisma: 8 } });
    } else {
      update({ abilityMethod: m });
    }
  };

  return (
    <div className="space-y-6">
      <div>
        <h2 className="text-2xl font-bold text-neutral-100">Ability Scores</h2>
        <p className="text-sm text-neutral-400 mt-1">Pick a generation method.</p>
      </div>

      <div className="flex gap-2 flex-wrap">
        {(["standardArray", "pointBuy", "rolled", "manual"] as AbilityMethod[]).map((m) => (
          <button
            key={m}
            onClick={() => setMethod(m)}
            className={`px-4 py-2 rounded border text-sm ${draft.abilityMethod === m ? "bg-amber-600/20 border-amber-500 text-amber-300" : "border-neutral-700 text-neutral-300"}`}
          >
            {m === "standardArray" ? "Standard Array" : m === "pointBuy" ? "Point Buy" : m === "rolled" ? "Rolled (4d6 drop 1)" : "Manual"}
          </button>
        ))}
      </div>

      {draft.abilityMethod === "standardArray" && <StandardArray />}
      {draft.abilityMethod === "pointBuy" && <PointBuy />}
      {draft.abilityMethod === "rolled" && <Rolled dice={dice} />}
      {draft.abilityMethod === "manual" && <Manual />}

      <AbilityImprovementSection
        species={species}
        classes={classes}
        backgrounds={backgrounds}
        subclasses={subclasses}
        features={features}
      />

      <ScoreSummary abilities={draft.abilities} />
    </div>
  );
}

interface AsiSlot {
  featureId: string;
  featureName: string;
  points: number;
  maxPerAbility: number;
  cap?: number;
}

function AbilityImprovementSection({
  species,
  classes,
  backgrounds,
  subclasses,
  features,
}: {
  species: import("@/types/content").Species[];
  classes: import("@/types/content").ClassDef[];
  backgrounds: import("@/types/content").Background[];
  subclasses: import("@/types/content").Subclass[];
  features: Record<string, import("@/types/content").Feature>;
}) {
  const { draft, update } = useCreator();
  const level = draft.classes[0]?.level ?? 1;
  const chosenClass = classes.find((c) => c.id === draft.classes[0]?.classId);
  const chosenSpecies = species.find((s) => s.id === draft.speciesId);
  const chosenBg = backgrounds.find((b) => b.id === draft.backgroundId);
  const chosenSubclassId = draft.classes[0]?.subclassId ??
    (chosenClass ? (() => {
      for (const lf of chosenClass.levelFeatures ?? []) {
        if (lf.level > level) continue;
        for (const fid of lf.featureIds) {
          const f = features[fid];
          if (f?.effects?.some((e) => e.target.kind === "grantSubclassChoice")) {
            const pick = draft.featureChoices[fid]?.[0];
            if (pick) return pick;
          }
        }
      }
      return undefined;
    })() : undefined);
  const chosenSubclass = subclasses.find((s) => s.id === chosenSubclassId);

  const activeFeatureIds = useMemo(() => {
    const ids: string[] = [];
    ids.push(...(chosenSpecies?.featureIds ?? []));
    ids.push(...(chosenBg?.featureIds ?? []));
    for (const lf of chosenClass?.levelFeatures ?? []) {
      if (lf.level <= level) ids.push(...lf.featureIds);
    }
    for (const lf of chosenSubclass?.levelFeatures ?? []) {
      if (lf.level <= level) ids.push(...lf.featureIds);
    }
    return ids;
  }, [chosenSpecies, chosenBg, chosenClass, chosenSubclass, level]);

  const asiSlots: AsiSlot[] = useMemo(() => {
    const out: AsiSlot[] = [];
    for (const fid of activeFeatureIds) {
      const f = features[fid];
      if (!f) continue;
      for (const eff of f.effects ?? []) {
        if (eff.target.kind === "abilityScoreChoice" && (eff.level ?? 1) <= level) {
          out.push({
            featureId: f.id,
            featureName: f.name,
            points: eff.target.points,
            maxPerAbility: eff.target.maxPerAbility,
            cap: eff.target.cap,
          });
        }
      }
    }
    return out;
  }, [activeFeatureIds, features, level]);

  if (asiSlots.length === 0) return null;

  const applyPatch = (featureId: string, next: string[]) => {
    update({ featureChoices: { ...draft.featureChoices, [featureId]: next } });
  };

  return (
    <div className="space-y-4">
      {asiSlots.map((slot) => {
        const picks = (draft.featureChoices[slot.featureId] ?? []) as Ability[];
        const counts: Partial<Record<Ability, number>> = {};
        for (const a of picks) counts[a] = (counts[a] ?? 0) + 1;
        const remaining = slot.points - picks.length;

        // Baseline = current draft ability + fixed bonuses from other active features
        // + picks from OTHER asi slots. Excludes this slot's own picks so the delta shown
        // for this slot lives on top of that baseline.
        const baseline: Record<Ability, number> = { ...draft.abilities };
        for (const fid of activeFeatureIds) {
          const f = features[fid];
          if (!f) continue;
          for (const eff of f.effects ?? []) {
            if ((eff.level ?? 1) > level) continue;
            if (eff.target.kind === "ability") {
              const delta =
                eff.operation === "decrease" ? -(eff.value ?? 0) : eff.value ?? 0;
              if (eff.operation === "set" && eff.value !== undefined) {
                baseline[eff.target.ability] = eff.value;
              } else {
                baseline[eff.target.ability] += delta;
              }
            } else if (eff.target.kind === "abilityScoreChoice" && f.id !== slot.featureId) {
              const otherPicks = (draft.featureChoices[f.id] ?? []) as Ability[];
              const otherCounts: Partial<Record<Ability, number>> = {};
              for (const a of otherPicks) otherCounts[a] = (otherCounts[a] ?? 0) + 1;
              for (const a of ABILITIES) {
                baseline[a] += Math.min(otherCounts[a] ?? 0, eff.target.maxPerAbility);
              }
            }
          }
        }

        const inc = (a: Ability) => {
          if (remaining <= 0) return;
          if ((counts[a] ?? 0) >= slot.maxPerAbility) return;
          if (slot.cap !== undefined && baseline[a] + (counts[a] ?? 0) + 1 > slot.cap) return;
          applyPatch(slot.featureId, [...picks, a]);
        };
        const dec = (a: Ability) => {
          const idx = picks.lastIndexOf(a);
          if (idx < 0) return;
          const next = [...picks];
          next.splice(idx, 1);
          applyPatch(slot.featureId, next);
        };

        return (
          <div key={slot.featureId} className="p-4 border border-emerald-500/40 bg-emerald-500/5 rounded">
            <div className="text-sm font-semibold text-emerald-300 mb-1">
              {slot.featureName} — distribute {slot.points} points (max {slot.maxPerAbility} per ability{slot.cap ? `, cap ${slot.cap}` : ""})
              <span className="ml-2 text-xs text-neutral-500">({picks.length}/{slot.points})</span>
            </div>
            <div className="grid grid-cols-3 md:grid-cols-6 gap-2 mt-3">
              {ABILITIES.map((a) => {
                const current = counts[a] ?? 0;
                const wouldBe = baseline[a] + current;
                const cappedOut = slot.cap !== undefined && wouldBe >= slot.cap;
                return (
                  <div key={a} className="p-2 border border-neutral-700 rounded text-center">
                    <div className="text-xs uppercase text-neutral-500">{a.slice(0, 3)}</div>
                    <div className="flex items-center justify-center gap-1 mt-1">
                      <button type="button" onClick={() => dec(a)} className="w-6 h-6 rounded bg-neutral-800 hover:bg-neutral-700">−</button>
                      <span className="text-lg font-bold w-6 text-emerald-300">+{current}</span>
                      <button
                        type="button"
                        onClick={() => inc(a)}
                        disabled={cappedOut || remaining <= 0 || current >= slot.maxPerAbility}
                        className="w-6 h-6 rounded bg-neutral-800 hover:bg-neutral-700 disabled:opacity-30 disabled:cursor-not-allowed"
                      >+</button>
                    </div>
                    <div className={`text-[10px] mt-1 ${cappedOut ? "text-red-400" : "text-neutral-500"}`}>
                      {wouldBe}{slot.cap !== undefined ? `/${slot.cap}` : ""}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ScoreSummary({ abilities }: { abilities: AbilityScores }) {
  return (
    <div className="grid grid-cols-3 md:grid-cols-6 gap-2">
      {ABILITIES.map((a) => (
        <div key={a} className="p-3 border border-neutral-700 rounded bg-neutral-900 text-center">
          <div className="text-xs uppercase text-neutral-500">{a.slice(0, 3)}</div>
          <div className="text-2xl font-bold text-neutral-100">{abilities[a]}</div>
          <div className="text-sm text-amber-400">{fmtMod(getAbilityModifier(abilities[a]))}</div>
        </div>
      ))}
    </div>
  );
}

function Manual() {
  const { draft, update } = useCreator();
  const set = (a: Ability, v: number) =>
    update({ abilities: { ...draft.abilities, [a]: v } });
  return (
    <div className="grid grid-cols-3 md:grid-cols-6 gap-3">
      {ABILITIES.map((a) => (
        <div key={a}>
          <label className="block text-xs uppercase text-neutral-400 mb-1">{a}</label>
          <input
            type="number"
            value={draft.abilities[a]}
            onChange={(e) => set(a, Number(e.target.value) || 0)}
            className="w-full bg-neutral-800 border border-neutral-700 rounded px-2 py-2 text-center text-lg"
          />
        </div>
      ))}
    </div>
  );
}

function StandardArray() {
  const { draft, update } = useCreator();
  const assignments = ABILITIES.map((a) => draft.abilities[a]);
  const remaining = [...STANDARD_ARRAY];
  for (const v of assignments) {
    const idx = remaining.indexOf(v);
    if (idx >= 0) remaining.splice(idx, 1);
  }

  const setAbility = (a: Ability, value: number) => {
    update({ abilities: { ...draft.abilities, [a]: value } });
  };

  return (
    <div className="space-y-3">
      <p className="text-sm text-neutral-400">
        Pool: <span className="font-mono text-neutral-200">{STANDARD_ARRAY.join(", ")}</span>
      </p>
      <div className="grid grid-cols-3 md:grid-cols-6 gap-3">
        {ABILITIES.map((a) => {
          const current = draft.abilities[a];
          const options = [8, ...new Set([...STANDARD_ARRAY, current])].sort((x, y) => y - x);
          return (
            <div key={a}>
              <label className="block text-xs uppercase text-neutral-400 mb-1">{a}</label>
              <select
                value={current}
                onChange={(e) => setAbility(a, Number(e.target.value))}
                className="w-full bg-neutral-800 border border-neutral-700 rounded px-2 py-2 text-center text-lg"
              >
                {options.map((v) => {
                  const used = assignments.filter((x) => x === v).length;
                  const inPool = STANDARD_ARRAY.filter((x) => x === v).length;
                  const disabled = v !== current && v !== 8 && used >= inPool;
                  return (
                    <option key={v} value={v} disabled={disabled}>{v}</option>
                  );
                })}
              </select>
            </div>
          );
        })}
      </div>
      <p className="text-xs text-neutral-500">Unassigned pool: {remaining.length > 0 ? remaining.join(", ") : "empty"}</p>
    </div>
  );
}

function PointBuy() {
  const { draft, update } = useCreator();
  const spent = useMemo(
    () => ABILITIES.reduce((sum, a) => sum + (POINT_BUY_COST[draft.abilities[a]] ?? 0), 0),
    [draft.abilities]
  );
  const remaining = POINT_BUY_BUDGET - spent;

  const adjust = (a: Ability, delta: number) => {
    const next = draft.abilities[a] + delta;
    if (next < 8 || next > 15) return;
    const nextCost = POINT_BUY_COST[next];
    const currentCost = POINT_BUY_COST[draft.abilities[a]];
    if (POINT_BUY_BUDGET - (spent - currentCost + nextCost) < 0) return;
    update({ abilities: { ...draft.abilities, [a]: next } });
  };

  return (
    <div className="space-y-3">
      <div className="text-sm">
        Points remaining: <span className={`font-bold ${remaining < 0 ? "text-red-400" : "text-amber-400"}`}>{remaining}</span> / {POINT_BUY_BUDGET}
      </div>
      <div className="grid grid-cols-3 md:grid-cols-6 gap-3">
        {ABILITIES.map((a) => (
          <div key={a} className="p-3 border border-neutral-700 rounded text-center">
            <div className="text-xs uppercase text-neutral-400">{a}</div>
            <div className="flex items-center justify-center gap-2 mt-2">
              <button onClick={() => adjust(a, -1)} className="w-7 h-7 rounded bg-neutral-800 hover:bg-neutral-700 text-lg">−</button>
              <span className="text-xl font-bold w-8">{draft.abilities[a]}</span>
              <button onClick={() => adjust(a, 1)} className="w-7 h-7 rounded bg-neutral-800 hover:bg-neutral-700 text-lg">+</button>
            </div>
            <div className="text-xs text-neutral-500 mt-1">cost {POINT_BUY_COST[draft.abilities[a]] ?? "—"}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

function Rolled({ dice }: { dice: ReturnType<typeof useDiceContext> }) {
  const { draft, update } = useCreator();
  const [pool, setPool] = useState<number[]>([]);
  const [assignments, setAssignments] = useState<(Ability | null)[]>(
    () => Array.from({ length: 6 }, () => null)
  );
  const [rolling, setRolling] = useState(false);

  const rollOne = async (): Promise<number> => {
    const roller = dice.rollerRef.current;
    if (roller) {
      try {
        const outcome = await roller.roll({ 6: 4 }, "Ability roll (4d6 drop lowest)");
        const rolls = outcome.roll.map((r) => r.value).sort((a, b) => b - a);
        return rolls[0] + rolls[1] + rolls[2];
      } catch {
        /* fall through */
      }
    }
    const rolls = Array.from({ length: 4 }, () => 1 + Math.floor(Math.random() * 6)).sort((a, b) => b - a);
    return rolls[0] + rolls[1] + rolls[2];
  };

  const rollNext = async () => {
    if (pool.length >= 6) return;
    setRolling(true);
    const v = await rollOne();
    setPool([...pool, v]);
    setRolling(false);
  };

  const setSlot = (i: number, v: number) => {
    const next = [...pool];
    next[i] = v;
    setPool(next);
  };

  const setAssignment = (i: number, a: Ability | null) => {
    const next = [...assignments];
    next[i] = a;
    setAssignments(next);
  };

  const applyAssignments = () => {
    const nextAbilities = { ...draft.abilities };
    for (let i = 0; i < 6; i++) {
      const a = assignments[i];
      const v = pool[i];
      if (a && typeof v === "number" && v > 0) nextAbilities[a] = v;
    }
    update({ abilities: nextAbilities });
  };

  const hasSomethingToApply = assignments.some((a, i) => a && (pool[i] ?? 0) > 0);

  return (
    <div className="space-y-4">
      <div className="flex gap-2 flex-wrap">
        <button
          onClick={rollNext}
          disabled={rolling || pool.length >= 6}
          className="px-4 py-2 text-sm bg-amber-600 hover:bg-amber-500 disabled:opacity-40 rounded text-neutral-900 font-semibold"
        >
          {rolling ? "Rolling..." : pool.length >= 6 ? "Pool full" : `Roll next (${pool.length}/6)`}
        </button>
        <button
          onClick={() => setPool([])}
          className="px-4 py-2 text-sm text-neutral-400 hover:text-neutral-200"
        >
          Clear
        </button>
      </div>

      <div>
        <label className="block text-sm text-neutral-400 mb-2">
          Pool (physical-dice players: enter values manually). Pick an ability under each slot to assign it.
        </label>
        <div className="grid grid-cols-3 md:grid-cols-6 gap-2">
          {Array.from({ length: 6 }).map((_, i) => (
            <div key={i} className="flex flex-col gap-1">
              <input
                type="number"
                min={3}
                max={18}
                value={pool[i] ?? ""}
                onChange={(e) => setSlot(i, Number(e.target.value) || 0)}
                placeholder="—"
                className="bg-neutral-800 border border-neutral-700 rounded px-2 py-2 text-center text-lg"
              />
              <select
                value={assignments[i] ?? ""}
                onChange={(e) => setAssignment(i, (e.target.value || null) as Ability | null)}
                className="bg-neutral-800 border border-neutral-700 rounded px-2 py-1 text-sm capitalize"
              >
                <option value="">---</option>
                {ABILITIES.map((a) => {
                  const takenByOther = assignments.some((x, k) => k !== i && x === a);
                  return (
                    <option key={a} value={a} disabled={takenByOther}>{a}</option>
                  );
                })}
              </select>
            </div>
          ))}
        </div>
      </div>

      <div>
        <button
          type="button"
          onClick={applyAssignments}
          disabled={!hasSomethingToApply}
          className="px-4 py-2 text-sm bg-amber-600 hover:bg-amber-500 disabled:opacity-40 rounded text-neutral-900 font-semibold"
        >
          Apply changes
        </button>
      </div>
    </div>
  );
}
