import { parseLlmJson, flattenValue } from "../lib/llm-parse";
import { useState } from "react";
import { invoke } from "@tauri-apps/api/core";
import { addToLore } from "../lib/lore";
import { useToast } from "./Toast";
import { addGeneration, extractTitle, type Generation } from "../lib/generations";
import { usePrefillEffect } from "../lib/usePrefill";

interface QuestStep {
  title: string;
  description: string;
  // ponytail: the LLM occasionally returns an object/array here despite the
  // prompt; coerce to string at use sites so React never renders a raw object.
  choice?: unknown;
}

interface QuestReward {
  xp: number;        // XP per character
  gold: number;      // total gold (split as the party sees fit)
  items: string[];   // magic items / treasure
  notes: string;     // any other reward (boons, favors, reputation)
}

interface QuestResponse {
  title: string;
  hook: string;
  steps: QuestStep[];
  twist: string;
  reward: string | QuestReward;
}

interface Props {
  prefill?: Generation | null;
  onPrefillConsumed?: () => void;
}

export function QuestDesigner({ prefill, onPrefillConsumed }: Props = {}) {
  const [theme, setTheme] = useState("");
  const [level, setLevel] = useState(5);
  const [partySize, setPartySize] = useState(4);
  const [quest, setQuest] = useState<QuestResponse | null>(null);
  const [currentStep, setCurrentStep] = useState(0);
  const [loading, setLoading] = useState(false);
  // ponytail: player-facing view hides the Twist + Choices so the DM can share
  // the screen without spoiling. Step status is derived from currentStep.
  const [playerView, setPlayerView] = useState(false);
  const { addToast } = useToast();

  usePrefillEffect(prefill ?? null, "quest", () => onPrefillConsumed?.(), (g) => {
    const parsed = parseLlmJson<QuestResponse>(g.data);
    if (parsed) {
      setQuest(parsed);
      setCurrentStep(0);
      addToast(`Loaded "${g.title}" from history`, "info");
    }
  });

  async function generate() {
    setLoading(true);
    setQuest(null);
    setCurrentStep(0);
    try {
      const result = await invoke<string>("generate", {
        req: {
          prompt: `Design a D&D quest for ${partySize} level ${level} characters.
${theme ? `Theme: ${theme}` : ""}

Provide the response as a JSON object with exactly these keys:
- "title": a catchy quest name
- "hook": 1-2 sentences describing how the party gets involved
- "steps": an array of 3-5 quest steps, each with "title" (string), "description" (2-3 sentence string), and optionally "choice" — a SINGLE short string describing a meaningful decision the party faces (e.g. "Spare the bandit or turn him in?"). "choice" MUST be a string or null, NEVER an array or object. Example step: {"title":"The Crossroads","description":"...","choice":"Fight or flee?"}
- "twist": a surprise revelation or complication
- "reward": an object with keys xp (number, XP awarded to EACH character), gold (number, total gp), items (array of strings, magic items or notable treasure), and notes (string, any other reward like boons or favors)

IMPORTANT: Return ONLY a raw JSON object. NO markdown fences, NO code blocks, NO extra text. Start with { and end with }.`,
          system: "You are a creative D&D quest designer. You MUST respond with ONLY valid JSON. No markdown fences, no code blocks, no explanation. Just the JSON object.",
          temperature: 0.85,
          max_tokens: 800,
        },
      });
      const parsed = parseLlmJson<QuestResponse>(result);
      if (parsed) {
        setQuest(parsed);
        addToast("Quest designed", "success");
        const title = extractTitle("quest", result, `Quest (lvl ${level})`);
        const source = `Level ${level}${theme ? `, ${theme}` : ""}`;
        void addGeneration({ kind: "quest", title, data: result, source });
        const steps = (parsed.steps || [])
          .map((s, i) => `${i + 1}. ${s.title}: ${s.description}${s.choice ? ` (Choice: ${flattenValue(s.choice)})` : ""}`)
          .join("\n");
        void addToLore(
          `Quest: ${parsed.title || "Untitled"}`,
          `Quest: ${parsed.title || "Untitled"} (level ${level}, ${partySize} PCs${theme ? `, ${theme}` : ""}).\nHook: ${parsed.hook}\n${steps}\nTwist: ${parsed.twist}\nReward: ${typeof parsed.reward === "string" ? parsed.reward : `XP ${parsed.reward?.xp}/each, ${parsed.reward?.gold} gp, items: ${(parsed.reward?.items || []).join(", ")}; ${parsed.reward?.notes || ""}`}`,
        );
      } else {
        addToast("LLM returned an unparseable response", "error");
      }
    } catch (e) {
      addToast(`Quest generation failed: ${e}`, "error");
    }
    setLoading(false);
  }

  return (
    <div className="flex flex-col gap-4">
      <div className="flex flex-col gap-2">
        <div className="grid grid-cols-3 gap-2">
          <div className="col-span-2 flex flex-col gap-1">
            <label className="text-[var(--color-text-secondary)] text-[10px] font-medium">Quest Theme</label>
            <input
              className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-dim)] focus:outline-none focus:border-[var(--color-gold-bright)] text-sm"
              value={theme}
              onChange={(e) => setTheme(e.target.value)}
              placeholder="e.g. haunted forest, political intrigue, dragon's lair..."
              onKeyDown={(e) => e.key === "Enter" && generate()}
            />
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-[var(--color-text-secondary)] text-[10px] font-medium">Party Level</label>
            <input
              type="number"
              min={1}
              max={20}
              value={level}
              onChange={(e) => setLevel(parseInt(e.target.value) || 1)}
              className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-gold-bright)] text-sm font-mono"
            />
          </div>
        </div>
        <div className="flex flex-col gap-1 max-w-32">
          <label className="text-[var(--color-text-secondary)] text-[10px] font-medium">Party Size</label>
          <input
            type="number"
            min={1}
            max={12}
            value={partySize}
            onChange={(e) => setPartySize(parseInt(e.target.value) || 1)}
            className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] px-3 py-2 text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-gold-bright)] text-sm font-mono"
          />
        </div>
        <button
          onClick={generate}
          disabled={loading}
          className="rounded-lg bg-[var(--color-gold-bright)] text-[var(--color-bg-deep)] px-4 py-2 text-sm font-semibold hover:bg-[var(--color-gold-muted)] transition-colors cursor-pointer disabled:opacity-50"
        >
          {loading ? "✨ Designing…" : "✨ Design Quest"}
        </button>
        {quest && (
          <button
            onClick={() => setPlayerView((v) => !v)}
            className={`rounded-lg px-3 py-2 text-xs font-semibold border transition-colors cursor-pointer ${
              playerView
                ? "bg-[var(--color-gold-glow)] border-[var(--color-gold-bright)] text-[var(--color-gold-bright)]"
                : "bg-[var(--color-bg-surface)] border-[var(--color-border-glass)] text-[var(--color-text-dim)] hover:text-[var(--color-text-secondary)]"
            }`}
            title="Hide the twist and choices for screen-sharing"
          >
            {playerView ? "👁 Player view" : "🖥 GM view"}
          </button>
        )}
      </div>

      {!quest && !loading && (
        <div className="flex flex-col items-center justify-center py-8 text-center text-[var(--color-text-dim)] text-xs">
          <span>No quest yet.</span>
          <span className="mt-1">Set the theme + scope, then Design Quest.</span>
        </div>
      )}


      {quest && (
        <div className="flex flex-col gap-3">
          {/* Quest title & hook */}
          <div className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] p-4">
            <h3 className="font-heading text-[var(--color-gold-bright)] text-lg font-bold mb-1">
              {quest.title}
            </h3>
            <p className="text-[var(--color-text-secondary)] text-sm italic leading-relaxed">
              {quest.hook}
            </p>
          </div>

          {/* Steps - step-through view */}
          {quest.steps?.length > 0 && (
            <div>
              <div className="flex items-center justify-between mb-2">
                <h4 className="text-[var(--color-text-secondary)] text-xs font-medium">
                  Quest Steps
                </h4>
                <div className="flex gap-1">
                  {quest.steps.map((_, i) => (
                    <button
                      key={i}
                      onClick={() => setCurrentStep(i)}
                      className={`w-6 h-6 rounded-full text-[10px] font-mono flex items-center justify-center cursor-pointer transition-colors ${
                        i === currentStep
                          ? "bg-[var(--color-gold-bright)] text-[var(--color-bg-deep)]"
                          : i < currentStep
                            ? "bg-[var(--color-success)]/20 text-[var(--color-success)]"
                            : "bg-[var(--color-bg-surface)] text-[var(--color-text-dim)] border border-[var(--color-border-subtle)]"
                      }`}
                    >
                      {i + 1}
                    </button>
                  ))}
                </div>
              </div>

              <div className="rounded-lg bg-[var(--color-bg-surface)] border border-[var(--color-border-glass)] p-4">
                <div className="flex items-center gap-2 mb-1">
                  <h5 className="text-[var(--color-text-primary)] text-sm font-semibold">
                    Step {currentStep + 1}: {quest.steps[currentStep].title}
                  </h5>
                  <span className="text-[9px] uppercase tracking-wider text-[var(--color-gold-bright)]">Active</span>
                </div>
                <p className="text-[var(--color-text-secondary)] text-sm leading-relaxed">
                  {quest.steps[currentStep].description}
                </p>
                {!!quest.steps[currentStep].choice && !playerView && (
                  <div className="mt-2 rounded-lg bg-[var(--color-bg-deep)] border-l-2 border-[var(--color-gold-bright)] px-3 py-2">
                    <span className="text-[var(--color-gold-bright)] text-[10px] font-medium uppercase tracking-wider">Choice</span>
                    <p className="text-[var(--color-text-primary)] text-sm mt-0.5">{flattenValue(quest.steps[currentStep].choice)}</p>
                  </div>
                )}
                <div className="flex justify-between mt-3">
                  <button
                    onClick={() => setCurrentStep(Math.max(0, currentStep - 1))}
                    disabled={currentStep === 0}
                    className="text-[var(--color-text-dim)] hover:text-[var(--color-text-primary)] text-xs cursor-pointer disabled:opacity-30 disabled:cursor-default"
                  >
                    ← Previous
                  </button>
                  <button
                    onClick={() => setCurrentStep(Math.min(quest.steps.length - 1, currentStep + 1))}
                    disabled={currentStep === quest.steps.length - 1}
                    className="text-[var(--color-gold-bright)] hover:text-[var(--color-gold-muted)] text-xs cursor-pointer disabled:opacity-30 disabled:cursor-default"
                  >
                    Next →
                  </button>
                </div>
              </div>
            </div>
          )}

          {/* Twist */}
          {quest.twist && !playerView && (
            <div className="rounded-lg border-l-2 border-[var(--color-danger)] bg-[var(--color-bg-surface)] px-4 py-3">
              <span className="text-[var(--color-danger)] text-[10px] font-medium uppercase tracking-wider">Twist</span>
              <p className="text-[var(--color-text-primary)] text-sm mt-0.5">{quest.twist}</p>
            </div>
          )}

          {/* Reward */}
          {quest.reward && (
            <div className="rounded-lg border-l-2 border-[var(--color-gold-bright)] bg-[var(--color-bg-surface)] px-4 py-3">
              <span className="text-[var(--color-gold-bright)] text-[10px] font-medium uppercase tracking-wider">Reward</span>
              {/* ponytail: structured reward breakdown if the LLM returned the
                  object form; fall back to a paragraph for older generations. */}
              {typeof quest.reward === "object" && quest.reward !== null && "xp" in quest.reward ? (
                <div className="mt-1 flex flex-col gap-1">
                  <div className="flex flex-wrap gap-x-4 gap-y-0.5 text-sm">
                    <span><span className="text-[var(--color-text-dim)]">XP</span> <span className="font-mono font-bold text-[var(--color-gold-bright)]">{quest.reward.xp}</span> <span className="text-[var(--color-text-dim)]">/ character</span></span>
                    <span><span className="text-[var(--color-text-dim)]">Gold</span> <span className="font-mono font-bold text-[var(--color-gold-bright)]">{quest.reward.gold} gp</span></span>
                  </div>
                  {quest.reward.items?.length > 0 && (
                    <div className="text-sm">
                      <span className="text-[var(--color-text-dim)]">Items: </span>
                      <span className="text-[var(--color-text-primary)]">{quest.reward.items.join(", ")}</span>
                    </div>
                  )}
                  {quest.reward.notes && (
                    <p className="text-[var(--color-text-secondary)] text-sm italic">{quest.reward.notes}</p>
                  )}
                </div>
              ) : (
                <p className="text-[var(--color-text-primary)] text-sm mt-0.5">{typeof quest.reward === "string" ? quest.reward : ""}</p>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}