"use client";

import clsx from "clsx";
import Link from "next/link";
import { useEffect, useState, type FormEvent } from "react";
import { Bot, ChevronDown, Copy, FlaskConical, Image as ImageIcon, MessageSquareText, MousePointerClick, Pencil, Plus, Search, Send, Trash2 } from "lucide-react";
import { Badge, Button, ConfirmDialog, Dialog, EmptyState, Field, Input, PageHeader, Panel, Select, Skeleton } from "@/components/ui/kit";
import { Menu } from "@/components/ui/menu";
import { useToast } from "@/components/ui/toast";
import { useSession } from "@/components/session";
import { BotReplyDialog, REPLY_TYPE_LABEL } from "@/components/bots/bot-reply-dialog";
import { api, qs } from "@/lib/api";
import { formatDateTime, formatPhone } from "@/lib/format";
import { useApi } from "@/lib/use-api";
import type { BotReply, ReplyType } from "@/lib/types";

const TYPE_ICON: Record<ReplyType, React.ReactNode> = { text: <MessageSquareText />, media: <ImageIcon />, interactive: <MousePointerClick /> };
const nf = new Intl.NumberFormat("en-IN");

type Match = { normalized: string; match: { id: number; name: string; reason: string } | null; also_matched: { id: number; name: string; trigger: string }[]; active_replies: number };

function Tester() {
  const [text, setText] = useState("");
  const [first, setFirst] = useState(false);
  const [result, setResult] = useState<Match | null>(null);
  const [busy, setBusy] = useState(false);
  async function run(e: FormEvent) {
    e.preventDefault();
    setBusy(true);
    try {
      setResult((await api.post<{ data: Match }>("/bot-replies/match", { text, first_message: first })).data);
    } finally {
      setBusy(false);
    }
  }
  return (
    <Panel className="p-5">
      <h2 className="flex items-center gap-2 font-semibold">
        <FlaskConical className="size-4 text-teal" /> Try a message
      </h2>
      <p className="mt-1 text-[13px] text-muted">See which reply a customer would get. Nothing is sent.</p>
      <form onSubmit={run} className="mt-3 space-y-2.5">
        <Input aria-label="Message to test" placeholder="e.g. What are your prices?" value={text} onChange={(e) => setText(e.target.value)} />
        <label className="flex items-center gap-2 text-[13px]">
          <input type="checkbox" className="size-4 accent-teal" checked={first} onChange={(e) => setFirst(e.target.checked)} />
          Their first message to us
        </label>
        <Button type="submit" size="sm" loading={busy} disabled={!text.trim() && !first}>
          Check
        </Button>
      </form>
      {result && (
        <div className="mt-4 rounded-lg bg-paper p-3 text-sm" aria-live="polite">
          {result.match ? (
            <>
              <p>
                Gets <span className="font-semibold text-ink">{result.match.name}</span>
              </p>
              <p className="mt-0.5 text-[13px] text-muted">Matched: {result.match.reason}</p>
              {result.also_matched.length > 0 && (
                <p className="mt-2 text-[13px] text-muted">
                  Also matched, lower priority: {result.also_matched.map((m) => `${m.name} (${m.trigger})`).join(", ")}
                </p>
              )}
            </>
          ) : (
            <p className="text-muted">No reply. {result.active_replies ? "None of the active triggers match." : "There are no active replies."}</p>
          )}
        </div>
      )}
      <details className="mt-4 text-[13px] text-muted">
        <summary className="cursor-pointer font-medium text-text">How replies are chosen</summary>
        <ol className="mt-2 list-decimal space-y-1 pl-5">
          <li>One reply per incoming message, never more.</li>
          <li>Exact match beats starts with, then ends with, then contains word, then contains.</li>
          <li>Within a type, the longer trigger wins; then a number-specific reply; then the older one.</li>
          <li>Welcome only fires for a first message that matched nothing else.</li>
          <li>STOP and other opt-out words never get a reply. Paused chats get none either.</li>
        </ol>
      </details>
    </Panel>
  );
}

function TestSendDialog({ reply, onClose }: { reply: BotReply; onClose: () => void }) {
  const toast = useToast();
  const { data } = useApi<{ data: { conversation_id: number; name: string; phone: string; account: string | null }[] }>("/bot-replies/test-recipients");
  const [to, setTo] = useState<number | null>(null);
  const [busy, setBusy] = useState(false);
  const list = data?.data ?? [];
  async function send() {
    if (!to) return;
    setBusy(true);
    try {
      await api.post(`/bot-replies/${reply.id}/test`, { conversation_id: to });
      toast("success", `Sent ${reply.name} as a test`);
      onClose();
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setBusy(false);
    }
  }
  return (
    <Dialog
      open
      onClose={onClose}
      title="Send a test"
      description="WhatsApp only allows replies like this within 24 hours of a customer's last message, so pick someone who wrote recently (message the number from your own phone first)."
      footer={
        <>
          <Button onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon={<Send className="size-4" />} disabled={!to} loading={busy} onClick={send}>
            Send test
          </Button>
        </>
      }
    >
      {!data ? (
        <Skeleton className="h-10 w-full" />
      ) : list.length === 0 ? (
        <p className="text-sm text-muted">Nobody has messaged you in the last 24 hours. Send a WhatsApp message to your business number, then try again.</p>
      ) : (
        <Field label="Send to" htmlFor="ts-to">
          <Select id="ts-to" value={to ?? ""} onChange={(e) => setTo(Number(e.target.value))}>
            <option value="" disabled>
              Choose a recent conversation
            </option>
            {list.map((c) => (
              <option key={c.conversation_id} value={c.conversation_id}>
                {c.name || formatPhone(c.phone)} ({formatPhone(c.phone)})
              </option>
            ))}
          </Select>
        </Field>
      )}
    </Dialog>
  );
}

export default function BotRepliesPage() {
  const { can } = useSession();
  const toast = useToast();
  const manage = can("bots.manage");
  const [term, setTerm] = useState("");
  const [q, setQ] = useState("");
  const [type, setType] = useState("");
  useEffect(() => {
    const t = setTimeout(() => setQ(term.trim()), 250);
    return () => clearTimeout(t);
  }, [term]);
  const { data, loading, reload } = useApi<{ data: BotReply[] }>(`/bot-replies${qs({ q, type })}`);
  const [editing, setEditing] = useState<{ reply?: BotReply; type: ReplyType } | null>(null);
  const [deleting, setDeleting] = useState<BotReply | null>(null);
  const [testing, setTesting] = useState<BotReply | null>(null);
  const [busy, setBusy] = useState<number | null>(null);
  const [warnings, setWarnings] = useState<string[]>([]);
  // Optimistic switch state until the reloaded row shows a change.
  const [flips, setFlips] = useState<Record<number, { value: BotReply["status"]; base: BotReply["status"] }>>({});
  const rows = (data?.data ?? []).map((r) => {
    const f = flips[r.id];
    return f && f.base === r.status ? { ...r, status: f.value } : r;
  });

  async function toggle(r: BotReply) {
    const next = r.status === "active" ? "inactive" : "active";
    setBusy(r.id);
    setFlips((m) => ({ ...m, [r.id]: { value: next, base: r.status } }));
    try {
      const res = await api.post<{ warnings: string[] }>(`/bot-replies/${r.id}/status`, { status: next });
      setWarnings(res.warnings ?? []);
      reload();
    } catch (e) {
      setFlips((m) => {
        const copy = { ...m };
        delete copy[r.id];
        return copy;
      });
      toast("error", (e as Error).message);
    } finally {
      setBusy(null);
    }
  }
  async function duplicate(r: BotReply) {
    try {
      const res = await api.post<{ data: BotReply }>(`/bot-replies/${r.id}/duplicate`);
      toast("success", "Copied. The copy is off until you change its trigger and switch it on.");
      reload();
      setEditing({ reply: res.data, type: res.data.reply_type });
    } catch (e) {
      toast("error", (e as Error).message);
    }
  }
  async function remove() {
    if (!deleting) return;
    setBusy(deleting.id);
    try {
      await api.delete(`/bot-replies/${deleting.id}`);
      toast("success", "Bot reply deleted");
      setDeleting(null);
      reload();
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setBusy(null);
    }
  }

  const createMenu = (
    <Menu
      trigger={(p) => (
        <Button variant="primary" icon={<Plus className="size-4" />} {...p}>
          New bot reply <ChevronDown className="-mr-1 size-4" />
        </Button>
      )}
      items={[
        { label: "Text reply", hint: "A message with contact details filled in", icon: <MessageSquareText />, onSelect: () => setEditing({ type: "text" }) },
        { label: "Media reply", hint: "An image, video, audio or document", icon: <ImageIcon />, onSelect: () => setEditing({ type: "media" }) },
        { label: "Interactive reply", hint: "Reply buttons, a link button or a list", icon: <MousePointerClick />, onSelect: () => setEditing({ type: "interactive" }) },
      ]}
    />
  );

  return (
    <>
      <PageHeader
        title="Bot replies"
        description={
          <>
            Answer common questions automatically. For multi-step conversations use{" "}
            <Link href="/bot-flows" className="font-medium text-teal hover:underline">
              bot flows
            </Link>
            .
          </>
        }
        actions={manage && createMenu}
      />
      {warnings.length > 0 && (
        <div className="mb-4 rounded-lg border border-amber/30 bg-amber-soft px-4 py-3 text-sm text-amber" role="status">
          <p className="font-medium">Saved. Heads up about trigger priority:</p>
          <ul className="mt-1 list-disc pl-5">
            {warnings.map((w) => (
              <li key={w}>{w}</li>
            ))}
          </ul>
          <button className="mt-1 text-[13px] font-medium underline" onClick={() => setWarnings([])}>
            Dismiss
          </button>
        </div>
      )}
      <div className="grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_300px]">
        <Panel>
          <div className="flex flex-col gap-3 border-b border-line px-5 py-4 sm:flex-row sm:items-center">
            <div className="relative flex-1">
              <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted" />
              <Input aria-label="Search bot replies" placeholder="Search name or trigger" className="w-full pl-9" value={term} onChange={(e) => setTerm(e.target.value)} />
            </div>
            <Select aria-label="Filter by type" className="sm:w-44" value={type} onChange={(e) => setType(e.target.value)}>
              <option value="">All types</option>
              <option value="text">Text</option>
              <option value="media">Media</option>
              <option value="interactive">Interactive</option>
            </Select>
          </div>
          {!data && loading ? (
            <div className="space-y-3 p-5">
              {[0, 1, 2].map((i) => (
                <Skeleton key={i} className="h-12 w-full" />
              ))}
            </div>
          ) : rows.length === 0 ? (
            <EmptyState
              icon={<Bot />}
              title={q || type ? "No matching replies" : "No bot replies yet"}
              body={q || type ? "Try a different search." : "Create a reply for questions you get every day: prices, opening hours, where you are."}
              action={!q && !type && manage ? createMenu : undefined}
            />
          ) : (
            <div className="relative overflow-x-auto">
              <table className="w-full min-w-[760px] text-sm">
                <thead className="border-b border-line text-left text-[13px] text-muted">
                  <tr>
                    <th className="px-5 py-3 font-medium">Reply</th>
                    <th className="px-3 py-3 font-medium">Trigger</th>
                    <th className="px-3 py-3 text-right font-medium">Sent</th>
                    <th className="px-3 py-3 font-medium">Status</th>
                    <th className="px-5 py-3 text-right font-medium">
                      <span className="sr-only">Actions</span>
                    </th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-line">
                  {rows.map((r) => (
                    <tr key={r.id} className={clsx(r.status === "inactive" && "text-muted")}>
                      <td className="max-w-[340px] px-5 py-3">
                        <div className="flex items-start gap-3">
                          <span className="mt-0.5 grid size-8 shrink-0 place-items-center rounded-md bg-teal-soft text-teal [&_svg]:size-4" title={REPLY_TYPE_LABEL[r.reply_type]}>
                            {TYPE_ICON[r.reply_type]}
                          </span>
                          <div className="min-w-0">
                            <button className={clsx("text-left font-medium hover:text-teal", r.status === "active" ? "text-ink" : "text-muted")} onClick={() => manage && setEditing({ reply: r, type: r.reply_type })} disabled={!manage}>
                              {r.name}
                            </button>
                            <p className="truncate text-[13px] text-muted">{r.summary}</p>
                          </div>
                        </div>
                      </td>
                      <td className="px-3 py-3">
                        <span className="text-[13px] text-muted">{r.trigger_label}</span>
                        {r.trigger_subject && <span className="block font-medium">“{r.trigger_subject}”</span>}
                        {r.whatsapp_account && <span className="block text-xs text-muted">Only on {r.whatsapp_account.display_phone_number}</span>}
                      </td>
                      <td className="tabular px-3 py-3 text-right" title={r.last_sent_at ? `Last sent ${formatDateTime(r.last_sent_at)}` : "Not sent yet"}>
                        {nf.format(r.sent_count)}
                      </td>
                      <td className="px-3 py-3">
                        {manage ? (
                          <label className="inline-flex cursor-pointer items-center gap-2">
                            <input type="checkbox" role="switch" className="size-4 accent-teal" checked={r.status === "active"} disabled={busy === r.id} onChange={() => toggle(r)} aria-label={`${r.name} active`} />
                            <span className="text-[13px]">{r.status === "active" ? "On" : "Off"}</span>
                          </label>
                        ) : (
                          <Badge tone={r.status === "active" ? "teal" : "neutral"}>{r.status === "active" ? "On" : "Off"}</Badge>
                        )}
                      </td>
                      <td className="px-5 py-3">
                        {manage && (
                          <div className="flex justify-end gap-1">
                            <button onClick={() => setTesting(r)} className="rounded p-1.5 text-muted hover:bg-paper hover:text-teal" aria-label={`Send ${r.name} as a test`} title="Send a test">
                              <Send className="size-4" />
                            </button>
                            <button onClick={() => setEditing({ reply: r, type: r.reply_type })} className="rounded p-1.5 text-muted hover:bg-paper hover:text-teal" aria-label={`Edit ${r.name}`} title="Edit">
                              <Pencil className="size-4" />
                            </button>
                            <button onClick={() => duplicate(r)} className="rounded p-1.5 text-muted hover:bg-paper hover:text-teal" aria-label={`Duplicate ${r.name}`} title="Duplicate">
                              <Copy className="size-4" />
                            </button>
                            <button onClick={() => setDeleting(r)} className="rounded p-1.5 text-muted hover:bg-paper hover:text-brick" aria-label={`Delete ${r.name}`} title="Delete">
                              <Trash2 className="size-4" />
                            </button>
                          </div>
                        )}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </Panel>
        <Tester />
      </div>

      {editing && (
        <BotReplyDialog
          key={editing.reply?.id ?? `new-${editing.type}`}
          initial={editing.reply}
          type={editing.type}
          onClose={() => setEditing(null)}
          onSaved={(r, w) => {
            toast("success", editing.reply ? `Saved ${r.name}` : `Created ${r.name}`);
            setWarnings(w);
            setEditing(null);
            reload();
          }}
        />
      )}
      {testing && <TestSendDialog reply={testing} onClose={() => setTesting(null)} />}
      <ConfirmDialog open={!!deleting} title="Delete this bot reply?" message={`“${deleting?.name}” stops answering immediately. Messages it already sent stay in the inbox.`} confirmLabel="Delete" loading={busy === deleting?.id} onConfirm={remove} onClose={() => setDeleting(null)} />
    </>
  );
}
