"use client";

import { useMemo, useRef, useState, type FormEvent } from "react";
import { Plus, Trash2 } from "lucide-react";
import { Button, Dialog, Field, Input, Select, Textarea } from "@/components/ui/kit";
import { useToast } from "@/components/ui/toast";
import { api, ApiError } from "@/lib/api";
import type { MessageTemplate } from "@/lib/types";
import { PreviewFrame, TemplateBubble } from "./template-preview";

type Btn = { type: "QUICK_REPLY"; text: string } | { type: "URL"; text: string; url: string; example?: string } | { type: "PHONE_NUMBER"; text: string; phone_number: string };

const VAR = /\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g;
const varsIn = (t: string) => [...new Set([...t.matchAll(VAR)].map((m) => m[1]))];

const LANGUAGES = [
  ["en_US", "English (US)"],
  ["en_GB", "English (UK)"],
  ["en", "English"],
  ["hi", "Hindi"],
  ["bn", "Bengali"],
  ["ta", "Tamil"],
  ["te", "Telugu"],
  ["mr", "Marathi"],
  ["gu", "Gujarati"],
  ["kn", "Kannada"],
  ["ml", "Malayalam"],
  ["pa", "Punjabi"],
  ["ur", "Urdu"],
  ["ar", "Arabic"],
  ["es", "Spanish"],
  ["pt_BR", "Portuguese (Brazil)"],
  ["fr", "French"],
  ["de", "German"],
  ["id", "Indonesian"],
] as const;

function fromTemplate(t: MessageTemplate) {
  const h = t.components.find((c) => c.type === "HEADER");
  const b = t.components.find((c) => c.type === "BODY");
  const f = t.components.find((c) => c.type === "FOOTER");
  const btns = t.components.find((c) => c.type === "BUTTONS")?.buttons ?? [];
  const bodyEx: Record<string, string> = {};
  const positional = b?.example?.body_text?.[0];
  if (b?.text && positional) varsIn(b.text).sort((x, y) => Number(x) - Number(y)).forEach((v, i) => (bodyEx[v] = positional[i] ?? ""));
  for (const p of b?.example?.body_text_named_params ?? []) bodyEx[p.param_name] = p.example;
  return {
    headerFormat: h?.format === "TEXT" ? "TEXT" : "NONE",
    headerText: h?.format === "TEXT" ? (h.text ?? "") : "",
    headerExample: h?.example?.header_text?.[0] ?? h?.example?.header_text_named_params?.[0]?.example ?? "",
    body: b?.text ?? "",
    examples: bodyEx,
    footer: f?.text ?? "",
    buttons: btns.map((x): Btn =>
      x.type === "URL" ? { type: "URL", text: x.text, url: x.url ?? "", example: x.example?.[0] ?? "" } : x.type === "PHONE_NUMBER" ? { type: "PHONE_NUMBER", text: x.text, phone_number: x.phone_number ?? "" } : { type: "QUICK_REPLY", text: x.text },
    ),
  };
}

/** Create a template, or edit one (mounted only while open). */
export function TemplateBuilder({ template, accountId, onClose, onSaved }: { template?: MessageTemplate; accountId?: number; onClose: () => void; onSaved: (t: MessageTemplate) => void }) {
  const toast = useToast();
  const init = template ? fromTemplate(template) : null;
  const [name, setName] = useState(template?.name ?? "");
  const [category, setCategory] = useState(template?.category ?? "UTILITY");
  const [language, setLanguage] = useState(template?.language ?? "en_US");
  const [headerFormat, setHeaderFormat] = useState<"NONE" | "TEXT">((init?.headerFormat as "NONE" | "TEXT") ?? "NONE");
  const [headerText, setHeaderText] = useState(init?.headerText ?? "");
  const [headerExample, setHeaderExample] = useState(init?.headerExample ?? "");
  const [body, setBody] = useState(init?.body ?? "");
  const [examples, setExamples] = useState<Record<string, string>>(init?.examples ?? {});
  const [footer, setFooter] = useState(init?.footer ?? "");
  const [buttons, setButtons] = useState<Btn[]>(init?.buttons ?? []);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [saving, setSaving] = useState(false);
  const bodyRef = useRef<HTMLTextAreaElement>(null);

  const bodyVars = useMemo(() => varsIn(body), [body]);
  const headerVars = headerFormat === "TEXT" ? varsIn(headerText) : [];
  const named = [...headerVars, ...bodyVars].some((v) => !/^\d+$/.test(v));

  function insertVariable() {
    const next = named ? "name" : String(Math.max(0, ...bodyVars.filter((v) => /^\d+$/.test(v)).map(Number)) + 1);
    const el = bodyRef.current;
    const at = el?.selectionStart ?? body.length;
    const value = `${body.slice(0, at)}{{${next}}}${body.slice(el?.selectionEnd ?? at)}`;
    setBody(value);
    requestAnimationFrame(() => {
      el?.focus();
      const pos = at + next.length + 4;
      el?.setSelectionRange(pos, pos);
    });
  }

  const fill = (t: string, ex: Record<string, string>) => t.replace(VAR, (m, k) => ex[k] || m);
  const sorted = [...buttons.filter((b) => b.type === "QUICK_REPLY"), ...buttons.filter((b) => b.type !== "QUICK_REPLY")];

  async function submit(e: FormEvent) {
    e.preventDefault();
    setSaving(true);
    setErrors({});
    const content = {
      header: headerFormat === "TEXT" ? { format: "TEXT", text: headerText, example: headerExample || undefined } : { format: "NONE" },
      body: { text: body, examples: Object.fromEntries(bodyVars.map((v) => [v, examples[v] ?? ""])) },
      footer: footer || undefined,
      buttons: buttons.map((b) => (b.type === "URL" ? { ...b, example: b.example || undefined } : b)),
    };
    try {
      const res = template
        ? await api.patch<{ data: MessageTemplate }>(`/templates/${template.id}`, content)
        : await api.post<{ data: MessageTemplate }>("/templates", { ...content, name, category, language, account_id: accountId });
      toast("success", template ? "Changes submitted to Meta for review" : "Template submitted to Meta for review");
      onSaved(res.data);
    } catch (err) {
      if (err instanceof ApiError && Object.keys(err.fields).length) setErrors(err.fields);
      else toast("error", (err as Error).message);
    } finally {
      setSaving(false);
    }
  }

  const err = (k: string) => errors[k];
  // Errors disappear as soon as the field (or anything under it) is edited.
  const clear = (prefix: string) =>
    setErrors((e) => (Object.keys(e).some((k) => k === prefix || k.startsWith(`${prefix}.`)) ? Object.fromEntries(Object.entries(e).filter(([k]) => k !== prefix && !k.startsWith(`${prefix}.`))) : e));
  const updateBtn = (i: number, patch: Partial<Btn>) => {
    clear(`buttons.${i}`);
    clear("buttons");
    setButtons((bs) => bs.map((b, j) => (j === i ? ({ ...b, ...patch } as Btn) : b)));
  };

  return (
    <Dialog
      open
      onClose={onClose}
      size="lg"
      title={template ? `Edit ${template.name}` : "New template"}
      description="Templates are reviewed by Meta before you can send them, usually within minutes and at most 24 hours."
      footer={
        <>
          <Button onClick={onClose}>Cancel</Button>
          <Button variant="primary" type="submit" form="tpl-form" loading={saving}>
            {template ? "Submit changes for review" : "Submit for review"}
          </Button>
        </>
      }
    >
      <div className="grid gap-6 md:grid-cols-[minmax(0,1fr)_300px]">
        <form id="tpl-form" onSubmit={submit} noValidate className="space-y-5">
          {!template && (
            <div className="grid gap-4 sm:grid-cols-3">
              <div className="sm:col-span-3">
                <Field label="Name" htmlFor="tp-name" error={err("name")} hint="Lowercase letters, numbers and underscores, e.g. order_shipped">
                  <Input id="tp-name" value={name} onChange={(e) => (clear("name"), setName(e.target.value.toLowerCase().replace(/\s+/g, "_")))} invalid={!!err("name")} autoFocus />
                </Field>
              </div>
              <div className="sm:col-span-2">
                <Field label="Category" htmlFor="tp-cat" hint={category === "MARKETING" ? "Promotions and offers. Never sent to opted-out contacts." : "Updates about something the customer did or asked for."}>
                  <Select id="tp-cat" value={category} onChange={(e) => setCategory(e.target.value as "MARKETING" | "UTILITY")}>
                    <option value="UTILITY">Utility</option>
                    <option value="MARKETING">Marketing</option>
                  </Select>
                </Field>
              </div>
              <Field label="Language" htmlFor="tp-lang" error={err("language")}>
                <Select id="tp-lang" value={language} onChange={(e) => setLanguage(e.target.value)}>
                  {LANGUAGES.map(([code, label]) => (
                    <option key={code} value={code}>
                      {label}
                    </option>
                  ))}
                </Select>
              </Field>
            </div>
          )}

          <fieldset className="space-y-3">
            <legend className="mb-1 text-[13px] font-medium">Header</legend>
            <div className="flex gap-2">
              {(["NONE", "TEXT"] as const).map((f) => (
                <label key={f} className={`cursor-pointer rounded-full border px-3 py-1 text-sm has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-mint ${headerFormat === f ? "border-teal bg-teal-soft text-teal" : "border-line text-muted"}`}>
                  <input type="radio" className="sr-only" checked={headerFormat === f} onChange={() => setHeaderFormat(f)} />
                  {f === "NONE" ? "No header" : "Text"}
                </label>
              ))}
            </div>
            {headerFormat === "TEXT" && (
              <div className="grid gap-3 sm:grid-cols-2">
                <Field label="Header text" htmlFor="tp-ht" error={err("header.text")} hint="Up to 60 characters, one variable at most.">
                  <Input id="tp-ht" value={headerText} onChange={(e) => (clear("header"), setHeaderText(e.target.value))} maxLength={60} invalid={!!err("header.text")} />
                </Field>
                {headerVars.length > 0 && (
                  <Field label={`Sample for {{${headerVars[0]}}}`} htmlFor="tp-hx" error={err("header.example")}>
                    <Input id="tp-hx" value={headerExample} onChange={(e) => (clear("header.example"), setHeaderExample(e.target.value))} invalid={!!err("header.example")} />
                  </Field>
                )}
              </div>
            )}
            <p className="text-[13px] text-muted">Image, video and document headers can be created in WhatsApp Manager and synced here.</p>
          </fieldset>

          <Field
            label="Body"
            htmlFor="tp-body"
            error={err("body.text")}
            hint={
              <span className="flex flex-wrap items-center justify-between gap-2">
                <span>{body.length}/1024. Use *bold*, _italic_ and variables for personal details.</span>
                <button type="button" onClick={insertVariable} className="inline-flex items-center gap-1 font-medium text-teal hover:underline">
                  <Plus className="size-3.5" /> Add variable
                </button>
              </span>
            }
          >
            <Textarea id="tp-body" ref={bodyRef} rows={5} value={body} onChange={(e) => (clear("body.text"), setBody(e.target.value))} maxLength={1024} invalid={!!err("body.text")} />
          </Field>

          {bodyVars.length > 0 && (
            <fieldset className="rounded-lg bg-paper p-4">
              <legend className="sr-only">Sample values</legend>
              <p className="mb-3 text-[13px] text-muted">Sample values help Meta understand the message. They are not sent to customers.</p>
              <div className="grid gap-3 sm:grid-cols-2">
                {bodyVars.map((v) => (
                  <Field key={v} label={`{{${v}}}`} htmlFor={`tp-ex-${v}`} error={err(`body.examples.${v}`)}>
                    <Input id={`tp-ex-${v}`} value={examples[v] ?? ""} onChange={(e) => (clear(`body.examples.${v}`), setExamples((x) => ({ ...x, [v]: e.target.value })))} invalid={!!err(`body.examples.${v}`)} />
                  </Field>
                ))}
              </div>
            </fieldset>
          )}

          <Field label="Footer" htmlFor="tp-foot" optional error={err("footer")} hint="Up to 60 characters, e.g. Reply STOP to unsubscribe">
            <Input id="tp-foot" value={footer} onChange={(e) => (clear("footer"), setFooter(e.target.value))} maxLength={60} />
          </Field>

          <fieldset className="space-y-3">
            <legend className="text-[13px] font-medium">
              Buttons <span className="font-normal text-muted">(optional)</span>
            </legend>
            {err("buttons") && <p className="text-[13px] text-brick">{err("buttons")}</p>}
            {buttons.map((b, i) => (
              <div key={i} className="grid gap-2 rounded-lg border border-line p-3 sm:grid-cols-[160px_1fr_auto]">
                <Select
                  aria-label="Button type"
                  className="w-full"
                  value={b.type}
                  onChange={(e) => {
                    const type = e.target.value as Btn["type"];
                    setButtons((bs) => bs.map((x, j) => (j === i ? (type === "URL" ? { type, text: x.text, url: "https://" } : type === "PHONE_NUMBER" ? { type, text: x.text, phone_number: "" } : { type, text: x.text }) : x)));
                  }}
                >
                  <option value="QUICK_REPLY">Quick reply</option>
                  <option value="URL">Visit website</option>
                  <option value="PHONE_NUMBER">Call</option>
                </Select>
                <Input aria-label="Button text" placeholder="Button text" value={b.text} maxLength={25} onChange={(e) => updateBtn(i, { text: e.target.value })} invalid={!!err(`buttons.${i}.text`)} />
                <Button type="button" variant="ghost" aria-label="Remove button" icon={<Trash2 className="size-4" />} onClick={() => setButtons((bs) => bs.filter((_, j) => j !== i))} />
                {b.type === "URL" && (
                  <div className="grid gap-2 sm:col-span-3 sm:grid-cols-2">
                    <Field label="URL" htmlFor={`tp-url-${i}`} error={err(`buttons.${i}.url`)} hint="Add {{1}} at the end for a per-contact link.">
                      <Input id={`tp-url-${i}`} value={b.url} onChange={(e) => updateBtn(i, { url: e.target.value })} invalid={!!err(`buttons.${i}.url`)} />
                    </Field>
                    {b.url.includes("{{1}}") && (
                      <Field label="Sample for {{1}}" htmlFor={`tp-urlx-${i}`} error={err(`buttons.${i}.example`)}>
                        <Input id={`tp-urlx-${i}`} value={b.example ?? ""} onChange={(e) => updateBtn(i, { example: e.target.value })} invalid={!!err(`buttons.${i}.example`)} />
                      </Field>
                    )}
                  </div>
                )}
                {b.type === "PHONE_NUMBER" && (
                  <div className="sm:col-span-3">
                    <Field label="Phone number" htmlFor={`tp-ph-${i}`} error={err(`buttons.${i}.phone_number`)} hint="With country code, e.g. 919812345670">
                      <Input id={`tp-ph-${i}`} inputMode="tel" value={b.phone_number} onChange={(e) => updateBtn(i, { phone_number: e.target.value })} invalid={!!err(`buttons.${i}.phone_number`)} />
                    </Field>
                  </div>
                )}
              </div>
            ))}
            {buttons.length < 10 && (
              <Button type="button" size="sm" icon={<Plus className="size-3.5" />} onClick={() => setButtons((bs) => [...bs, { type: "QUICK_REPLY", text: "" }])}>
                Add button
              </Button>
            )}
          </fieldset>
        </form>

        <aside className="md:sticky md:top-0 md:self-start">
          <p className="mb-2 text-[13px] font-medium text-muted">Preview with sample values</p>
          <PreviewFrame>
            <TemplateBubble
              header={headerFormat === "TEXT" ? fill(headerText, headerVars[0] ? { [headerVars[0]]: headerExample } : {}) : null}
              body={fill(body, examples)}
              footer={footer || null}
              buttons={sorted.map((b) => ({ type: b.type, text: b.text }))}
            />
          </PreviewFrame>
        </aside>
      </div>
    </Dialog>
  );
}
