"use client";

import clsx from "clsx";
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { ChevronLeft, ChevronRight, Contact as ContactIcon, Download, MessageCircle, Plus, Search, Send, Upload, X } from "lucide-react";
import { Badge, Button, ConfirmDialog, EmptyState, PageHeader, Panel, Select, Skeleton } from "@/components/ui/kit";
import { useToast } from "@/components/ui/toast";
import { useSession } from "@/components/session";
import { ContactForm } from "@/components/contacts/contact-form";
import { ContactDrawer } from "@/components/contacts/contact-drawer";
import { ConsentBadge } from "@/components/contacts/consent-badge";
import { ExportDialog, ImportDialog } from "@/components/contacts/import-export";
import { SendTemplateDialog } from "@/components/templates/send-template-dialog";
import { api, qs } from "@/lib/api";
import { useApi } from "@/lib/use-api";
import { countries, flag, formatDate, formatPhone } from "@/lib/format";
import type { Contact, CustomField, Group, Paginated } from "@/lib/types";

interface Filters {
  q: string;
  group_id: string;
  opt_in_status: string;
  country: string;
  archived: "exclude" | "only";
  page: number;
  per_page: number;
}

const initialFilters: Filters = { q: "", group_id: "", opt_in_status: "", country: "", archived: "exclude", page: 1, per_page: 25 };

export default function ContactsPage() {
  // useSearchParams needs a Suspense boundary when the route is prerendered.
  return (
    <Suspense fallback={<PageHeader title="Contacts" />}>
      <ContactsFromUrl />
    </Suspense>
  );
}

/**
 * Deep links such as /contacts?opt_in_status=opted_out (from the dashboard) seed the filters.
 * Keyed on the param so a new link remounts the view even when Next.js preserved its state.
 */
function ContactsFromUrl() {
  const params = useSearchParams();
  const status = params.get("opt_in_status") ?? "";
  const q = params.get("q") ?? "";
  return <ContactsView key={`${status}|${q}`} initialStatus={status} initialQuery={q} />;
}

function ContactsView({ initialStatus, initialQuery }: { initialStatus: string; initialQuery: string }) {
  const { can } = useSession();
  const toast = useToast();
  const router = useRouter();
  const [filters, setFilters] = useState<Filters>(() => ({ ...initialFilters, opt_in_status: initialStatus, q: initialQuery }));
  const [search, setSearch] = useState(initialQuery);
  const [templateFor, setTemplateFor] = useState<Contact | null>(null);
  const [opening, setOpening] = useState<number | null>(null);
  const waAccounts = useApi<{ data: { status: string }[] }>(can("whatsapp.view") ? "/whatsapp/accounts" : null);
  const hasWhatsApp = Boolean(waAccounts.data?.data.some((a) => a.status !== "disconnected"));
  const noWhatsAppTitle = "Connect a WhatsApp number in WhatsApp setup first";

  async function openChat(c: Contact) {
    setOpening(c.id);
    try {
      const r = await api.post<{ data: { id: number } }>("/inbox/start", { contact_id: c.id });
      router.push(`/inbox?c=${r.data.id}`);
    } catch (e) {
      toast("error", (e as Error).message);
      setOpening(null);
    }
  }
  const [selected, setSelected] = useState<Set<number>>(new Set());

  const [formOpen, setFormOpen] = useState(false);
  const [editing, setEditing] = useState<Contact | null>(null);
  const [drawerId, setDrawerId] = useState<number | null>(null);
  const [drawerVersion, setDrawerVersion] = useState(0);
  const [toDelete, setToDelete] = useState<Contact | null>(null);
  const [bulkDelete, setBulkDelete] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [exportOpen, setExportOpen] = useState(false);
  const [bulkGroup, setBulkGroup] = useState("");

  const countryList = useMemo(() => countries(), []);
  const closeDrawer = useCallback(() => setDrawerId(null), []);

  const list = useApi<Paginated<Contact>>(
    `/contacts${qs({
      q: filters.q,
      group_id: filters.group_id,
      opt_in_status: filters.opt_in_status,
      country: filters.country,
      archived: filters.archived,
      page: filters.page,
      per_page: filters.per_page,
    })}`,
  );
  const groupsReq = useApi<{ data: Group[] }>("/groups");
  const fieldsReq = useApi<{ data: CustomField[] }>("/custom-fields");
  const result = list.data ?? null;
  const loading = list.loading;
  const loadError = list.error ?? null;
  const groups = groupsReq.data?.data ?? [];
  const customFields = fieldsReq.data?.data ?? [];
  const load = list.reload;
  const loadMeta = () => {
    groupsReq.reload();
    fieldsReq.reload();
  };
  const refreshAll = () => {
    setSelected(new Set());
    load();
    loadMeta();
  };

  // Debounce the search box into filters (state is set inside the timer callback).
  useEffect(() => {
    const t = setTimeout(() => {
      setFilters((f) => (f.q === search.trim() ? f : { ...f, q: search.trim(), page: 1 }));
      setSelected(new Set());
    }, 300);
    return () => clearTimeout(t);
  }, [search]);

  const setFilter = <K extends keyof Filters>(k: K, v: Filters[K]) => {
    setSelected(new Set());
    setFilters((f) => ({ ...f, [k]: v, page: k === "page" ? (v as number) : 1 }));
  };
  const activeFilters = Boolean(filters.q || filters.group_id || filters.opt_in_status || filters.country || filters.archived === "only");

  const rows = result?.data ?? [];
  const allSelected = rows.length > 0 && rows.every((r) => selected.has(r.id));
  const toggleAll = () => setSelected(allSelected ? new Set() : new Set(rows.map((r) => r.id)));
  const toggle = (id: number) =>
    setSelected((s) => {
      const n = new Set(s);
      if (n.has(id)) n.delete(id);
      else n.add(id);
      return n;
    });

  async function bulk(action: string, extra: Record<string, unknown> = {}, message: string) {
    try {
      const r = await api.post<{ affected: number }>("/contacts/bulk", { action, ids: [...selected], ...extra });
      toast("success", message.replace("{n}", String(r.affected)));
      refreshAll();
    } catch (e) {
      toast("error", (e as Error).message);
    }
  }

  async function confirmDelete() {
    setDeleting(true);
    try {
      if (bulkDelete) {
        await bulk("delete", {}, "{n} contacts deleted");
      } else if (toDelete) {
        await api.delete(`/contacts/${toDelete.id}`);
        toast("success", "Contact deleted");
        if (drawerId === toDelete.id) setDrawerId(null);
        refreshAll();
      }
      setToDelete(null);
      setBulkDelete(false);
    } catch (e) {
      toast("error", (e as Error).message);
    } finally {
      setDeleting(false);
    }
  }

  return (
    <>
      <PageHeader
        title="Contacts"
        description="Everyone you can message on WhatsApp. Phone numbers are unique, and opted-out contacts are never sent campaigns."
        actions={
          <>
            {can("contacts.import") && (
              <Button icon={<Upload className="size-4" />} onClick={() => setImportOpen(true)}>
                Import
              </Button>
            )}
            {can("contacts.export") && (
              <Button icon={<Download className="size-4" />} onClick={() => setExportOpen(true)}>
                Export
              </Button>
            )}
            {can("contacts.manage") && (
              <Button
                variant="primary"
                icon={<Plus className="size-4" />}
                onClick={() => {
                  setEditing(null);
                  setFormOpen(true);
                }}
              >
                Add contact
              </Button>
            )}
          </>
        }
      />

      <Panel>
        {/* Toolbar */}
        <div className="flex flex-wrap items-center gap-2 border-b border-line p-3">
          <label className="relative min-w-[220px] flex-1">
            <span className="sr-only">Search contacts</span>
            <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted" />
            <input
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search name, phone or email"
              className="h-9 w-full rounded-md border border-line bg-white pl-9 pr-3 text-sm focus:border-teal focus:outline-none focus:ring-2 focus:ring-teal/15"
            />
          </label>
          <Select aria-label="Group" className="!h-9 w-auto min-w-36" value={filters.group_id} onChange={(e) => setFilter("group_id", e.target.value)}>
            <option value="">All groups</option>
            {groups.map((g) => (
              <option key={g.id} value={g.id}>
                {g.name} ({g.contacts_count})
              </option>
            ))}
          </Select>
          <Select aria-label="Consent" className="!h-9 w-auto min-w-36" value={filters.opt_in_status} onChange={(e) => setFilter("opt_in_status", e.target.value)}>
            <option value="">Any consent</option>
            <option value="opted_in">Opted in</option>
            <option value="unknown">Unknown</option>
            <option value="opted_out">Opted out</option>
          </Select>
          <Select aria-label="Country" className="!h-9 w-auto min-w-36 max-w-48" value={filters.country} onChange={(e) => setFilter("country", e.target.value)}>
            <option value="">All countries</option>
            {countryList.map((c) => (
              <option key={c.code} value={c.code}>
                {c.name}
              </option>
            ))}
          </Select>
          <Select aria-label="Archived" className="!h-9 w-auto" value={filters.archived} onChange={(e) => setFilter("archived", e.target.value as Filters["archived"])}>
            <option value="exclude">Active</option>
            <option value="only">Archived</option>
          </Select>
          {activeFilters && (
            <Button
              size="sm"
              variant="ghost"
              icon={<X className="size-3.5" />}
              onClick={() => {
                setSearch("");
                setSelected(new Set());
                setFilters(initialFilters);
              }}
            >
              Clear
            </Button>
          )}
        </div>

        {/* Bulk bar */}
        {selected.size > 0 && (
          <div className="flex flex-wrap items-center gap-2 border-b border-line bg-teal-soft/60 px-3 py-2 text-sm">
            <span className="mr-2 font-medium text-teal">{selected.size} selected</span>
            {can("contacts.manage") && groups.length > 0 && (
              <div className="flex items-center gap-1">
                <Select aria-label="Group for selected" className="!h-8 w-auto text-[13px]" value={bulkGroup} onChange={(e) => setBulkGroup(e.target.value)}>
                  <option value="">Choose group</option>
                  {groups.map((g) => (
                    <option key={g.id} value={g.id}>
                      {g.name}
                    </option>
                  ))}
                </Select>
                <Button size="sm" disabled={!bulkGroup} onClick={() => bulk("add_to_group", { group_id: Number(bulkGroup) }, "Added {n} contacts to the group")}>
                  Add to group
                </Button>
                <Button size="sm" disabled={!bulkGroup} onClick={() => bulk("remove_from_group", { group_id: Number(bulkGroup) }, "Removed {n} contacts from the group")}>
                  Remove
                </Button>
              </div>
            )}
            {can("contacts.manage") && (
              <>
                <Button size="sm" onClick={() => bulk("opt_out", {}, "{n} contacts opted out")}>
                  Opt out
                </Button>
                {filters.archived === "only" ? (
                  <Button size="sm" onClick={() => bulk("restore", {}, "{n} contacts restored")}>
                    Restore
                  </Button>
                ) : (
                  <Button size="sm" onClick={() => bulk("archive", {}, "{n} contacts archived")}>
                    Archive
                  </Button>
                )}
              </>
            )}
            {can("contacts.delete") && (
              <Button size="sm" variant="danger" onClick={() => setBulkDelete(true)}>
                Delete
              </Button>
            )}
          </div>
        )}

        {/* Table */}
        {loadError ? (
          <div className="p-8 text-center text-sm">
            <p className="text-brick">{loadError}</p>
            <Button size="sm" className="mt-3" onClick={load}>
              Try again
            </Button>
          </div>
        ) : !loading && rows.length === 0 ? (
          activeFilters ? (
            <EmptyState icon={<Search className="size-5" />} title="No contacts match these filters" body="Try a different search, or clear the filters to see everyone." />
          ) : (
            <EmptyState
              icon={<ContactIcon className="size-5" />}
              title="Add your first contacts"
              body="Add people one at a time, or import an Excel file. You'll need contacts before you can run campaigns or chat."
              action={
                can("contacts.manage") && (
                  <div className="flex gap-2">
                    {can("contacts.import") && <Button onClick={() => setImportOpen(true)}>Import from Excel</Button>}
                    <Button variant="primary" onClick={() => setFormOpen(true)}>
                      Add contact
                    </Button>
                  </div>
                )
              }
            />
          )
        ) : (
          <div className="relative overflow-x-auto">
            <table className="w-full min-w-[860px] text-sm">
              <thead>
                <tr className="border-b border-line text-left text-[13px] text-muted">
                  <th className="w-10 py-2.5 pl-4 pr-1">
                    <input type="checkbox" aria-label="Select all on this page" checked={allSelected} onChange={toggleAll} className="size-4 accent-teal" />
                  </th>
                  <th className="px-3 py-2.5 font-medium">Name</th>
                  <th className="px-3 py-2.5 font-medium">WhatsApp number</th>
                  <th className="px-3 py-2.5 font-medium">Country</th>
                  <th className="px-3 py-2.5 font-medium">Groups</th>
                  <th className="px-3 py-2.5 font-medium">Consent</th>
                  <th className="px-3 py-2.5 font-medium">Added</th>
                  <th className="px-3 py-2.5 pr-4 text-right font-medium">
                    <span className="sr-only">Actions</span>
                  </th>
                </tr>
              </thead>
              <tbody>
                {loading && !result
                  ? Array.from({ length: 6 }).map((_, i) => (
                      <tr key={i} className="border-b border-line last:border-0">
                        <td colSpan={8} className="px-4 py-3">
                          <Skeleton className="h-5 w-full" />
                        </td>
                      </tr>
                    ))
                  : rows.map((c) => (
                      <tr key={c.id} className={clsx("border-b border-line last:border-0 hover:bg-paper/70", selected.has(c.id) && "bg-teal-soft/40", loading && "opacity-60")}>
                        <td className="py-2.5 pl-4 pr-1">
                          <input type="checkbox" aria-label={`Select ${c.full_name}`} checked={selected.has(c.id)} onChange={() => toggle(c.id)} className="size-4 accent-teal" />
                        </td>
                        <td className="px-3 py-2.5">
                          <button onClick={() => setDrawerId(c.id)} className="text-left font-medium text-ink hover:text-teal hover:underline">
                            {c.full_name}
                          </button>
                          {c.email && <div className="max-w-[220px] truncate text-xs text-muted">{c.email}</div>}
                        </td>
                        <td className="tabular whitespace-nowrap px-3 py-2.5">{formatPhone(c.phone)}</td>
                        <td className="whitespace-nowrap px-3 py-2.5">{c.country ? `${flag(c.country)} ${c.country_name}` : <span className="text-muted">—</span>}</td>
                        <td className="px-3 py-2.5">
                          <div className="flex max-w-[220px] flex-wrap gap-1">
                            {c.groups.length ? c.groups.slice(0, 2).map((g) => <Badge key={g.id} tone="teal">{g.name}</Badge>) : <span className="text-muted">—</span>}
                            {c.groups.length > 2 && <Badge>+{c.groups.length - 2}</Badge>}
                          </div>
                        </td>
                        <td className="px-3 py-2.5">
                          <ConsentBadge status={c.opt_in_status} />
                        </td>
                        <td className="whitespace-nowrap px-3 py-2.5 text-muted">{formatDate(c.created_at)}</td>
                        <td className="whitespace-nowrap px-3 py-2.5 pr-4 text-right">
                          <div className="inline-flex items-center gap-1">
                            {can("inbox.reply") && (
                              <button
                                disabled={!hasWhatsApp}
                                onClick={() => setTemplateFor(c)}
                                title={hasWhatsApp ? "Send template message" : noWhatsAppTitle}
                                aria-label={`Send template message to ${c.full_name}`}
                                className="rounded p-1.5 text-muted hover:bg-teal-soft hover:text-teal disabled:text-muted/40 disabled:hover:bg-transparent"
                              >
                                <Send className="size-4" />
                              </button>
                            )}
                            {can("inbox.view") && (
                              <button
                                disabled={!hasWhatsApp || opening === c.id}
                                onClick={() => openChat(c)}
                                title={hasWhatsApp ? "Open chat" : noWhatsAppTitle}
                                aria-label={`Chat with ${c.full_name}`}
                                className="rounded p-1.5 text-muted hover:bg-teal-soft hover:text-teal disabled:text-muted/40 disabled:hover:bg-transparent"
                              >
                                <MessageCircle className="size-4" />
                              </button>
                            )}
                            {can("contacts.manage") && (
                              <Button
                                size="sm"
                                variant="ghost"
                                onClick={() => {
                                  setEditing(c);
                                  setFormOpen(true);
                                }}
                              >
                                Edit
                              </Button>
                            )}
                            {can("contacts.delete") && (
                              <Button size="sm" variant="ghost" className="hover:bg-brick-soft hover:text-brick" onClick={() => setToDelete(c)}>
                                Delete
                              </Button>
                            )}
                          </div>
                        </td>
                      </tr>
                    ))}
              </tbody>
            </table>
          </div>
        )}

        {/* Pagination */}
        {result && result.meta.total > 0 && (
          <div className="flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3 text-sm text-muted">
            <div className="flex items-center gap-2">
              <span className="tabular whitespace-nowrap">
                {(result.meta.page - 1) * result.meta.per_page + 1}–{Math.min(result.meta.page * result.meta.per_page, result.meta.total)} of {result.meta.total}
              </span>
              <Select aria-label="Rows per page" className="!h-8 w-auto text-[13px]" value={filters.per_page} onChange={(e) => setFilter("per_page", Number(e.target.value))}>
                {[25, 50, 100].map((n) => (
                  <option key={n} value={n}>
                    {n} per page
                  </option>
                ))}
              </Select>
            </div>
            <div className="flex items-center gap-1">
              <Button size="sm" aria-label="Previous page" disabled={filters.page <= 1} onClick={() => setFilter("page", filters.page - 1)} icon={<ChevronLeft className="size-4" />} />
              <span className="tabular whitespace-nowrap px-2">
                Page {result.meta.page} of {result.meta.last_page}
              </span>
              <Button size="sm" aria-label="Next page" disabled={filters.page >= result.meta.last_page} onClick={() => setFilter("page", filters.page + 1)} icon={<ChevronRight className="size-4" />} />
            </div>
          </div>
        )}
      </Panel>

      {formOpen && (
        <ContactForm
          key={editing?.id ?? "new"}
          open
          contact={editing}
          groups={groups}
          customFields={customFields}
          onClose={() => setFormOpen(false)}
          onSaved={() => {
            setFormOpen(false);
            refreshAll();
            setDrawerVersion((v) => v + 1);
          }}
          onOpenExisting={(id) => {
            setFormOpen(false);
            setDrawerId(id);
          }}
        />
      )}
      {drawerId && (
        <ContactDrawer
          key={`${drawerId}-${drawerVersion}`}
          contactId={drawerId}
          customFields={customFields}
          onClose={closeDrawer}
          onEdit={(c) => {
            setEditing(c);
            setFormOpen(true);
          }}
          onDelete={(c) => setToDelete(c)}
          onChanged={load}
        />
      )}
      <ConfirmDialog
        open={Boolean(toDelete) || bulkDelete}
        title={bulkDelete ? `Delete ${selected.size} contacts?` : "Delete this contact?"}
        message={
          bulkDelete ? (
            "Their details, group memberships and activity history will be removed permanently. Archive instead if you may need them later."
          ) : (
            <>
              <span className="font-medium text-text">{toDelete?.full_name}</span> and their activity history will be removed permanently. Archive instead if you may need them later.
            </>
          )
        }
        confirmLabel="Delete permanently"
        loading={deleting}
        onConfirm={confirmDelete}
        onClose={() => {
          setToDelete(null);
          setBulkDelete(false);
        }}
      />
      <ImportDialog
        open={importOpen}
        onClose={() => setImportOpen(false)}
        onImported={refreshAll}
      />
      <ExportDialog open={exportOpen} onClose={() => setExportOpen(false)} />
      {templateFor && (
        <SendTemplateDialog
          contactId={templateFor.id}
          contactName={templateFor.full_name}
          onClose={() => setTemplateFor(null)}
          onSent={() => setTemplateFor(null)}
        />
      )}
    </>
  );
}
