"use client";

import { useEffect, useRef, useState, type FormEvent } from "react";
import { Info, RotateCcw, Send, X } from "lucide-react";
import { Button, Input } from "@/components/ui/kit";
import { ReplyBubble } from "@/components/bots/reply-preview";
import { api } from "@/lib/api";
import type { BotAsset, FlowDraft, InteractiveContent, PreviewEvent, PreviewState } from "@/lib/types";

/**
 * Chat-style preview of the current canvas (saved or not). Runs on the server with the real interpreter
 * but sends nothing and changes no contacts. Delays are skipped.
 */
export function PreviewPanel({ flowId, draft, assets, onClose, onAt }: { flowId: number; draft: () => FlowDraft; assets: Record<number, BotAsset>; onClose: () => void; onAt: (nodeId: string | null) => void }) {
  const [events, setEvents] = useState<PreviewEvent[]>([]);
  const [state, setState] = useState<PreviewState | null>(null);
  const [text, setText] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const bottom = useRef<HTMLDivElement>(null);
  const started = useRef(false);

  async function step(input: { text?: string; reply_id?: string } | null, restart = false) {
    setBusy(true);
    setError(null);
    try {
      const r = await api.post<{ data: { events: PreviewEvent[]; state: PreviewState } }>(`/bot-flows/${flowId}/preview`, { draft: draft(), state: restart ? null : state, input });
      setEvents((e) => (restart ? r.data.events : [...e, ...r.data.events]));
      setState(r.data.state);
      onAt(r.data.state.waiting ? r.data.state.node_id : null);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  // Start once when opened (a ref guards React's dev double-invoke; state is only set in the request callback).
  useEffect(() => {
    if (started.current) return;
    started.current = true;
    void Promise.resolve().then(() => step(null, true));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  useEffect(() => bottom.current?.scrollIntoView({ block: "end" }), [events]);

  function submit(e: FormEvent) {
    e.preventDefault();
    if (!text.trim() || !state?.waiting) return;
    const t = text.trim();
    setText("");
    void step({ text: t });
  }

  // The last bot message is the one whose buttons can be tapped.
  const lastMessageIndex = events.map((e) => e.kind).lastIndexOf("message");

  return (
    <div className="flex h-full min-h-0 flex-col" aria-label="Flow preview">
      <header className="flex items-center gap-2 border-b border-line px-4 py-3">
        <h2 className="flex-1 font-semibold">Preview</h2>
        <Button size="sm" icon={<RotateCcw className="size-3.5" />} onClick={() => step(null, true)} disabled={busy}>
          Restart
        </Button>
        <button onClick={onClose} className="rounded p-1 text-muted hover:bg-paper" aria-label="Close preview">
          <X className="size-5" />
        </button>
      </header>
      <p className="flex items-start gap-2 border-b border-line bg-paper px-4 py-2 text-xs text-muted">
        <Info className="mt-0.5 size-3.5 shrink-0" />
        Uses what&apos;s on the canvas now, with a sample contact (Asha, India). Nothing is sent or saved; delays are skipped.
      </p>
      <div className="min-h-0 flex-1 space-y-2 overflow-y-auto bg-[#efeae2] p-3 [background-image:radial-gradient(#d9d2c5_1px,transparent_1px)] [background-size:14px_14px]" aria-live="polite">
        {events.map((ev, i) => {
          if (ev.kind === "note")
            return (
              <p key={i} className="mx-auto w-fit max-w-[90%] rounded-md bg-white/80 px-2 py-1 text-center text-[11.5px] text-[#54656f]">
                {ev.text}
              </p>
            );
          if (ev.kind === "customer")
            return (
              <div key={i} className="flex justify-end">
                <div className="max-w-[80%] rounded-lg rounded-tr-none bg-[#d9fdd3] px-3 py-1.5 text-[14px] shadow-sm">{ev.text}</div>
              </div>
            );
          const tappable = i === lastMessageIndex && state?.waiting && ev.type === "interactive";
          const a = ev.type === "interactive" ? (ev.content as InteractiveContent).action : null;
          return (
            <div key={i}>
              <ReplyBubble type={ev.type} content={ev.content} assets={assets} />
              {tappable && a?.type === "buttons" && (
                <div className="mt-1.5 flex max-w-[300px] flex-wrap gap-1.5">
                  {a.buttons.map((b) => (
                    <button key={b.id} disabled={busy} onClick={() => step({ reply_id: b.id, text: b.title })} className="rounded-full bg-white px-3 py-1 text-[13px] font-medium text-[#027eb5] shadow-sm hover:bg-[#f0f9ff]">
                      {b.title}
                    </button>
                  ))}
                </div>
              )}
              {tappable && a?.type === "list" && (
                <div className="mt-1.5 flex max-w-[300px] flex-wrap gap-1.5">
                  {a.sections.flatMap((s) => s.rows).map((r) => (
                    <button key={r.id} disabled={busy} onClick={() => step({ reply_id: r.id, text: r.title })} className="rounded-full bg-white px-3 py-1 text-[13px] font-medium text-[#027eb5] shadow-sm hover:bg-[#f0f9ff]">
                      {r.title}
                    </button>
                  ))}
                </div>
              )}
            </div>
          );
        })}
        {error && <p className="rounded-md bg-brick-soft px-3 py-2 text-[13px] text-brick">{error}</p>}
        <div ref={bottom} />
      </div>
      <form onSubmit={submit} className="flex gap-2 border-t border-line p-3">
        <Input aria-label="Reply as the customer" placeholder={state?.waiting ? "Reply as the customer" : state?.done ? "Flow finished. Restart to try again." : "…"} value={text} onChange={(e) => setText(e.target.value)} disabled={!state?.waiting || busy} className="flex-1" />
        <Button type="submit" variant="primary" icon={<Send className="size-4" />} disabled={!state?.waiting || busy || !text.trim()} aria-label="Send reply" />
      </form>
    </div>
  );
}
