"use client";

import clsx from "clsx";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { AlertTriangle, ArrowLeft, Copy, Download, Pause, Pencil, Play, Search, Trash2, XCircle } from "lucide-react";
import { Badge, Button, ConfirmDialog, Input, Panel, Skeleton } from "@/components/ui/kit";
import { useToast } from "@/components/ui/toast";
import { useSession } from "@/components/session";
import { api, download, qs } from "@/lib/api";
import { formatDateTime, formatDateTimeIn, formatPhone } from "@/lib/format";
import { useApi } from "@/lib/use-api";
import type { Campaign, CampaignRecipient } from "@/lib/types";
import { CampaignStatusBadge, pct } from "./campaign-status";

const nf = new Intl.NumberFormat("en-IN");
const RECIPIENT_FILTERS = [
  ["", "All"],
  ["pending", "Queued"],
  ["sent", "Sent"],
  ["delivered", "Delivered"],
  ["read", "Read"],
  ["failed", "Failed"],
  ["skipped", "Skipped"],
] as const;
const RECIPIENT_TONE: Record<CampaignRecipient["status"], { label: string; tone: "teal" | "amber" | "brick" | "neutral" }> = {
  pending: { label: "Queued", tone: "neutral" },
  sent: { label: "Sent", tone: "neutral" },
  delivered: { label: "Delivered", tone: "teal" },
  read: { label: "Read", tone: "teal" },
  failed: { label: "Failed", tone: "brick" },
  skipped: { label: "Skipped", tone: "amber" },
};

type Action = "pause" | "resume" | "cancel" | "duplicate" | "delete";

function Recipients({ campaignId, version }: { campaignId: number; version: number }) {
  const [status, setStatus] = useState("");
  const [term, setTerm] = useState("");
  const [q, setQ] = useState("");
  const [page, setPage] = useState(1);
  useEffect(() => {
    const t = setTimeout(() => setQ(term.trim()), 300);
    return () => clearTimeout(t);
  }, [term]);
  const { data, reload } = useApi<{ data: CampaignRecipient[]; meta: { total: number; last_page: number } }>(`/campaigns/${campaignId}/recipients${qs({ status: status || undefined, q: q || undefined, page })}`);
  useEffect(() => {
    if (version) reload();
  }, [version, reload]);
  const rows = data?.data ?? [];

  return (
    <Panel>
      <header className="flex flex-col gap-3 border-b border-line px-5 py-4 md:flex-row md:items-center md:justify-between">
        <h2 className="font-semibold">Recipients</h2>
        <div className="relative md:w-64">
          <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted" />
          <Input aria-label="Search recipients" placeholder="Name or number" className="pl-9" value={term} onChange={(e) => (setTerm(e.target.value), setPage(1))} />
        </div>
      </header>
      <div className="flex gap-1 overflow-x-auto border-b border-line px-4 py-2" role="tablist" aria-label="Filter recipients">
        {RECIPIENT_FILTERS.map(([v, l]) => (
          <button key={v} role="tab" aria-selected={status === v} onClick={() => (setStatus(v), setPage(1))} className={clsx("shrink-0 rounded-full px-3 py-1 text-[13px]", status === v ? "bg-ink text-white" : "text-muted hover:bg-paper")}>
            {l}
          </button>
        ))}
      </div>
      {!data ? (
        <div className="space-y-2 p-5">
          {[0, 1, 2, 3].map((i) => (
            <Skeleton key={i} className="h-9 w-full" />
          ))}
        </div>
      ) : rows.length === 0 ? (
        <p className="px-5 py-10 text-center text-sm text-muted">No recipients match.</p>
      ) : (
        <div className="relative overflow-x-auto">
          <table className="w-full min-w-[680px] text-sm">
            <thead className="text-left text-[13px] text-muted">
              <tr>
                <th className="px-5 py-2.5 font-medium">Contact</th>
                <th className="px-3 py-2.5 font-medium">Status</th>
                <th className="px-3 py-2.5 font-medium">Last update</th>
                <th className="px-5 py-2.5 font-medium">Details</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-line border-t border-line">
              {rows.map((r) => (
                <tr key={r.id}>
                  <td className="px-5 py-2.5">
                    <span className="block font-medium">{r.name || formatPhone(r.phone)}</span>
                    {r.name && <span className="tabular text-[13px] text-muted">{formatPhone(r.phone)}</span>}
                  </td>
                  <td className="px-3 py-2.5">
                    <Badge tone={RECIPIENT_TONE[r.status].tone}>{RECIPIENT_TONE[r.status].label}</Badge>
                  </td>
                  <td className="tabular px-3 py-2.5 text-muted">{formatDateTime(r.read_at ?? r.delivered_at ?? r.sent_at)}</td>
                  <td className="max-w-[320px] px-5 py-2.5 text-[13px] text-muted">{r.reason ?? (r.attempts > 1 ? `Sent after ${r.attempts} attempts` : "")}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
      {data && data.meta.last_page > 1 && (
        <footer className="flex items-center justify-between border-t border-line px-5 py-3 text-sm text-muted">
          <span className="tabular">
            {nf.format(data.meta.total)} recipients, page {page} of {data.meta.last_page}
          </span>
          <div className="flex gap-2">
            <Button size="sm" disabled={page <= 1} onClick={() => setPage(page - 1)}>
              Previous
            </Button>
            <Button size="sm" disabled={page >= data.meta.last_page} onClick={() => setPage(page + 1)}>
              Next
            </Button>
          </div>
        </footer>
      )}
    </Panel>
  );
}

function Stat({ label, value, sub, tone }: { label: string; value: number; sub?: string; tone?: "brick" | "amber" }) {
  return (
    <div className="rounded-lg border border-line bg-white p-4">
      <p className="text-[13px] text-muted">{label}</p>
      <p className={clsx("tabular mt-1 text-2xl font-semibold tracking-tight", tone === "brick" && value ? "text-brick" : tone === "amber" && value ? "text-amber" : "text-ink")}>{nf.format(value)}</p>
      {sub && <p className="tabular mt-0.5 text-xs text-muted">{sub}</p>}
    </div>
  );
}

function Reasons({ title, items }: { title: string; items: { reason: string; count: number }[] }) {
  if (!items.length) return null;
  return (
    <Panel className="p-5">
      <h2 className="mb-3 font-semibold">{title}</h2>
      <ul className="space-y-2 text-sm">
        {items.map((r) => (
          <li key={r.reason} className="flex justify-between gap-4">
            <span className="text-muted">{r.reason}</span>
            <span className="tabular font-medium">{nf.format(r.count)}</span>
          </li>
        ))}
      </ul>
    </Panel>
  );
}

export function CampaignReport() {
  const { id } = useParams<{ id: string }>();
  const router = useRouter();
  const toast = useToast();
  const { can } = useSession();
  const { data, error, reload } = useApi<{ data: Campaign }>(`/campaigns/${id}`);
  const [confirm, setConfirm] = useState<Action | null>(null);
  const [busy, setBusy] = useState<Action | null>(null);
  const [version, setVersion] = useState(0);
  const c = data?.data;
  const live = c?.status === "running" || c?.status === "scheduled";

  // Poll while sending so the numbers move; also refresh the recipient table.
  useEffect(() => {
    if (!live) return;
    const t = setInterval(() => {
      reload();
      setVersion((v) => v + 1);
    }, 3000);
    return () => clearInterval(t);
  }, [live, reload]);

  async function act(action: Action) {
    if (!c) return;
    setBusy(action);
    try {
      if (action === "delete") {
        await api.delete(`/campaigns/${c.id}`);
        toast("success", "Campaign deleted");
        router.push("/campaigns");
        return;
      }
      const r = await api.post<{ data: Campaign }>(`/campaigns/${c.id}/${action}`);
      if (action === "duplicate") {
        toast("success", "Copied as a new draft");
        router.push(`/campaigns/${r.data.id}/edit`);
        return;
      }
      toast("success", { pause: "Campaign paused", resume: "Sending resumed", cancel: "Campaign cancelled" }[action]);
      reload();
      setVersion((v) => v + 1);
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setBusy(null);
      setConfirm(null);
    }
  }

  if (error) return <p className="rounded-md bg-brick-soft px-4 py-3 text-sm text-brick">{error}</p>;
  if (!c)
    return (
      <div className="space-y-4">
        <Skeleton className="h-10 w-72" />
        <Skeleton className="h-28 w-full" />
        <Skeleton className="h-72 w-full" />
      </div>
    );

  const s = c.stats ?? { total: 0, pending: 0, skipped: 0, sent: 0, delivered: 0, read: 0, failed: 0 };
  const reach = s.total - s.skipped;
  const manage = can("campaigns.manage");

  return (
    <>
      <Link href="/campaigns" className="mb-3 inline-flex items-center gap-1.5 text-sm text-muted hover:text-teal">
        <ArrowLeft className="size-4" /> Campaigns
      </Link>
      <header className="mb-6 flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-3">
            <h1 className="text-2xl font-semibold tracking-tight text-ink">{c.title}</h1>
            <CampaignStatusBadge status={c.status} />
          </div>
          <dl className="mt-2 flex flex-wrap gap-x-6 gap-y-1 text-sm">
            <div className="flex gap-1.5">
              <dt className="text-muted">Template</dt>
              <dd>
                {c.template.name} ({c.template.language})
              </dd>
            </div>
            {c.status === "scheduled" ? (
              <div className="flex gap-1.5">
                <dt className="text-muted">Sends</dt>
                <dd>
                  {formatDateTimeIn(c.scheduled_at, c.timezone)} ({c.timezone.replace(/_/g, " ")})
                </dd>
              </div>
            ) : (
              c.started_at && (
                <div className="flex gap-1.5">
                  <dt className="text-muted">Started</dt>
                  <dd>{formatDateTime(c.started_at)}</dd>
                </div>
              )
            )}
            {c.completed_at && (
              <div className="flex gap-1.5">
                <dt className="text-muted">Finished</dt>
                <dd>{formatDateTime(c.completed_at)}</dd>
              </div>
            )}
            {c.created_by_name && (
              <div className="flex gap-1.5">
                <dt className="text-muted">Created by</dt>
                <dd>{c.created_by_name}</dd>
              </div>
            )}
          </dl>
        </div>
        <div className="flex flex-wrap gap-2">
          {manage && c.status === "scheduled" && (
            <Button icon={<Pencil className="size-4" />} onClick={() => router.push(`/campaigns/${c.id}/edit`)}>
              Edit
            </Button>
          )}
          {manage && c.status === "running" && (
            <Button icon={<Pause className="size-4" />} loading={busy === "pause"} onClick={() => act("pause")}>
              Pause
            </Button>
          )}
          {manage && c.status === "paused" && (
            <Button variant="primary" icon={<Play className="size-4" />} loading={busy === "resume"} onClick={() => act("resume")}>
              Resume
            </Button>
          )}
          {manage && ["scheduled", "running", "paused"].includes(c.status) && (
            <Button icon={<XCircle className="size-4" />} onClick={() => setConfirm("cancel")}>
              Cancel campaign
            </Button>
          )}
          {s.total > 0 && (
            <Button icon={<Download className="size-4" />} onClick={() => download(`/campaigns/${c.id}/export`, `campaign-${c.id}.xlsx`).catch((e: Error) => toast("error", e.message))}>
              Export
            </Button>
          )}
          {manage && (
            <Button icon={<Copy className="size-4" />} loading={busy === "duplicate"} onClick={() => act("duplicate")}>
              Duplicate
            </Button>
          )}
          {manage && ["draft", "scheduled", "cancelled"].includes(c.status) && (
            <Button variant="ghost" icon={<Trash2 className="size-4" />} aria-label="Delete campaign" onClick={() => setConfirm("delete")} />
          )}
        </div>
      </header>

      {c.status === "paused" && c.last_error && (
        <div className="mb-6 flex items-start gap-3 rounded-lg border border-amber/30 bg-amber-soft px-4 py-3 text-sm text-amber">
          <AlertTriangle className="mt-0.5 size-4 shrink-0" />
          <div>
            <p className="font-medium">Sending paused automatically</p>
            <p className="mt-0.5">{c.last_error}</p>
          </div>
        </div>
      )}
      {c.status === "draft" && (
        <p className="mb-6 rounded-lg bg-white px-4 py-3 text-sm text-muted ring-1 ring-line">
          This is a draft.{" "}
          {manage && (
            <Link href={`/campaigns/${c.id}/edit`} className="font-medium text-teal hover:underline">
              Finish setting it up
            </Link>
          )}
        </p>
      )}

      {s.total > 0 && (
        <>
          <div className="mb-3 grid grid-cols-2 gap-3 md:grid-cols-3 xl:grid-cols-6">
            <Stat label="Recipients" value={reach} sub={s.skipped ? `${nf.format(s.skipped)} skipped` : undefined} />
            <Stat label="Queued" value={s.pending} />
            <Stat label="Sent" value={s.sent} sub={`${pct(s.sent, reach)}% of recipients`} />
            <Stat label="Delivered" value={s.delivered} sub={`${pct(s.delivered, s.sent)}% of sent`} />
            <Stat label="Read" value={s.read} sub={`${pct(s.read, s.delivered)}% of delivered`} />
            <Stat label="Failed" value={s.failed} tone="brick" sub={s.failed ? `${pct(s.failed, reach)}% of recipients` : undefined} />
          </div>
          {reach > 0 && (
            <div className="mb-6 flex h-2.5 overflow-hidden rounded-full bg-white ring-1 ring-line" role="img" aria-label={`${s.sent} of ${reach} sent`}>
              <div className="bg-teal transition-[width]" style={{ width: `${(s.read / reach) * 100}%` }} />
              <div className="bg-mint transition-[width]" style={{ width: `${((s.delivered - s.read) / reach) * 100}%` }} />
              <div className="bg-[#9fd9c6] transition-[width]" style={{ width: `${((s.sent - s.delivered) / reach) * 100}%` }} />
              <div className="bg-brick transition-[width]" style={{ width: `${(s.failed / reach) * 100}%` }} />
            </div>
          )}
          <div className="grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_320px]">
            <Recipients campaignId={c.id} version={version} />
            <div className="space-y-6">
              <Reasons title="Why some were skipped" items={c.skipped_reasons ?? []} />
              <Reasons title="Why some failed" items={c.failure_reasons ?? []} />
            </div>
          </div>
        </>
      )}

      {confirm === "cancel" && (
        <ConfirmDialog
          open
          title="Cancel this campaign?"
          message="Messages already sent stay sent. Everyone still in the queue is skipped. This can't be undone, but you can duplicate the campaign later."
          confirmLabel="Cancel campaign"
          loading={busy === "cancel"}
          onConfirm={() => act("cancel")}
          onClose={() => setConfirm(null)}
        />
      )}
      {confirm === "delete" && (
        <ConfirmDialog open title="Delete this campaign?" message="It will be removed along with its recipient list." confirmLabel="Delete" loading={busy === "delete"} onConfirm={() => act("delete")} onClose={() => setConfirm(null)} />
      )}
    </>
  );
}
