import { Button, Card, Chip, Input, Separator, toast } from "@heroui/react";
import { Icon } from "@iconify/react";
import axios from "axios";
import AdminLayout from "components/layout/AdminLayout";
import Link from "next/link";
import { useCallback, useEffect, useRef, useState } from "react";
import EditModal from "./EditModal";
import DeleteModal from "./DeleteModal";
import ImportModal from "./ImportModal";
import {
  CATEGORY_LABELS,
  formatPrice,
  indexRegistrars,
  registrarName,
  TLD_CATEGORIES,
} from "@/lib/tld-pricing";
import { ADMIN_SELECT_SM } from "./styles";

const PER_PAGE = 25;

const SORTS = [
  { value: "popularity", label: "Popularity" },
  { value: "tld", label: "A-Z" },
  { value: "registration.price", label: "Registration price" },
  { value: "renewal.price", label: "Renewal price" },
  { value: "transfer.price", label: "Transfer price" },
];

// Admin editor for the TLD price comparison table. Rows are paginated straight
// from the API — the table holds ~1,400 extensions, so nothing is ever loaded
// into the browser in bulk.
export default function TldPricing() {
  const [rows, setRows] = useState([]);
  const [registrars, setRegistrars] = useState({});
  const [symbol, setSymbol] = useState("$");
  const [total, setTotal] = useState(0);
  const [totalPages, setTotalPages] = useState(1);
  const [fetching, setFetching] = useState(true);

  const [search, setSearch] = useState("");
  const [debouncedSearch, setDebouncedSearch] = useState("");
  const [category, setCategory] = useState("all");
  const [sort, setSort] = useState("popularity");
  const [page, setPage] = useState(1);

  const [editOpen, setEditOpen] = useState(false);
  const [editRow, setEditRow] = useState(null);
  const [saving, setSaving] = useState(false);

  const [deleteOpen, setDeleteOpen] = useState(false);
  const [deleteTld, setDeleteTld] = useState("");
  const [deleting, setDeleting] = useState(false);

  const [importOpen, setImportOpen] = useState(false);
  const [importing, setImporting] = useState(false);

  const requestId = useRef(0);

  useEffect(() => {
    axios
      .get("/api/tld-pricing/config")
      .then((res) => {
        setRegistrars(indexRegistrars(res.data?.registrars));
        setSymbol(res.data?.settings?.symbol || "$");
      })
      .catch((err) => console.log(err));
  }, []);

  useEffect(() => {
    const id = setTimeout(() => setDebouncedSearch(search), 300);
    return () => clearTimeout(id);
  }, [search]);

  useEffect(() => {
    setPage(1);
  }, [debouncedSearch, category, sort]);

  const load = useCallback(() => {
    const id = ++requestId.current;
    setFetching(true);

    axios
      .get("/api/tld-pricing", {
        params: {
          search: debouncedSearch,
          category,
          sort,
          dir: sort === "popularity" ? "desc" : "asc",
          page,
          limit: PER_PAGE,
          includeDisabled: 1,
        },
      })
      .then((res) => {
        if (id !== requestId.current) return;
        setRows(Array.isArray(res.data?.rows) ? res.data.rows : []);
        setTotal(res.data?.total || 0);
        setTotalPages(res.data?.totalPages || 1);
      })
      .catch((err) => {
        if (id !== requestId.current) return;
        console.log(err);
        setRows([]);
      })
      .finally(() => {
        if (id === requestId.current) setFetching(false);
      });
  }, [debouncedSearch, category, sort, page]);

  useEffect(() => {
    load();
  }, [load]);

  const handleSave = (form) => {
    setSaving(true);
    axios
      .post("/api/tld-pricing", { row: form })
      .then((res) => {
        toast.success(res.data?.message || "Saved");
        setEditOpen(false);
        load();
      })
      .catch((err) => {
        console.log(err);
        toast.error(err?.response?.data?.message || "Some error occurred.");
      })
      .finally(() => setSaving(false));
  };

  const handleDelete = () => {
    setDeleting(true);
    axios
      .delete("/api/tld-pricing", { params: { tld: deleteTld } })
      .then((res) => {
        toast.success(res.data?.message || "Deleted");
        setDeleteOpen(false);
        load();
      })
      .catch((err) => {
        console.log(err);
        toast.error("Some error occurred.");
      })
      .finally(() => setDeleting(false));
  };

  const handleImport = (mode) => {
    setImporting(true);
    axios
      .post("/api/tld-pricing/seed", { mode })
      .then((res) => {
        toast.success(res.data?.message || "Imported");
        setImportOpen(false);
        setPage(1);
        load();
      })
      .catch((err) => {
        console.log(err);
        toast.error(err?.response?.data?.message || "Import failed.");
      })
      .finally(() => setImporting(false));
  };

  // Flip a row's visibility without opening the editor.
  const toggleEnabled = (row) => {
    const next = { ...row, enabled: !row.enabled };
    setRows((prev) => prev.map((r) => (r.tld === row.tld ? next : r)));

    axios.post("/api/tld-pricing", { row: next }).catch((err) => {
      console.log(err);
      toast.error("Could not update visibility.");
      setRows((prev) => prev.map((r) => (r.tld === row.tld ? row : r)));
    });
  };

  const priceCell = (offer) => {
    const price = formatPrice(offer?.price, symbol);
    if (!price) return <span className="text-gray-300">—</span>;
    return (
      <div className="flex flex-col">
        <span className="font-mono text-sm font-medium">{price}</span>
        <span className="text-xs text-gray-500">
          {registrarName(registrars, offer?.registrar) || "—"}
        </span>
      </div>
    );
  };

  return (
    <AdminLayout>
      <EditModal
        isOpen={editOpen}
        onOpenChange={setEditOpen}
        row={editRow}
        registrars={registrars}
        onSave={handleSave}
        loading={saving}
      />
      <DeleteModal
        isOpen={deleteOpen}
        onOpenChange={setDeleteOpen}
        tld={deleteTld}
        handleDelete={handleDelete}
        loading={deleting}
      />
      <ImportModal
        isOpen={importOpen}
        onOpenChange={setImportOpen}
        handleImport={handleImport}
        loading={importing}
      />

      <Card>
        <Card.Header className="flex w-full flex-col gap-4">
          <div className="flex w-full flex-col gap-3 md:flex-row md:items-center md:justify-between">
            <div>
              <h4 className="text-xl font-semibold">TLD Pricing</h4>
              <p className="text-sm text-gray-500">
                Registration, renewal and transfer prices shown in the price
                comparison table on the home page.
              </p>
            </div>

            <div className="flex flex-wrap items-center gap-2">
              <Link href="/admin/tld-pricing/registrars">
                <Button variant="tertiary" className="rounded-full">
                  <Icon className="size-4" icon="mdi:storefront-outline" />
                  Registrars &amp; settings
                </Button>
              </Link>
              <Button
                variant="tertiary"
                onPress={() => setImportOpen(true)}
                className="rounded-full"
              >
                <Icon className="size-4" icon="mdi:database-import-outline" />
                Import TLDs
              </Button>
              <Button
                onPress={() => {
                  setEditRow(null);
                  setEditOpen(true);
                }}
                className="rounded-full"
              >
                <Icon className="size-4" icon="mdi:plus" />
                Add TLD
              </Button>
            </div>
          </div>

          <div className="flex w-full flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
            <div className="w-full lg:max-w-xs">
              <Input
                variant="secondary"
                type="text"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
                placeholder="Search extension…"
              />
            </div>

            <div className="flex flex-wrap items-center gap-2">
              {TLD_CATEGORIES.map((c) => (
                <button
                  key={c.value}
                  type="button"
                  onClick={() => setCategory(c.value)}
                  className={
                    "cursor-pointer rounded-full px-3 py-1.5 text-xs font-medium transition " +
                    (category === c.value
                      ? "bg-gray-900 text-white dark:bg-ink-50 dark:text-ink-900"
                      : "border border-gray-200 text-gray-600 hover:bg-gray-50 dark:border-ink-700 dark:text-ink-300 dark:hover:bg-ink-800")
                  }
                >
                  {c.label}
                </button>
              ))}

              <select
                value={sort}
                onChange={(e) => setSort(e.target.value)}
                aria-label="Sort by"
                className={ADMIN_SELECT_SM}
              >
                {SORTS.map((s) => (
                  <option key={s.value} value={s.value}>
                    Sort: {s.label}
                  </option>
                ))}
              </select>
            </div>
          </div>
        </Card.Header>

        <Separator />

        <Card.Content>
          {fetching && rows.length === 0 ? (
            <div className="flex items-center gap-2 py-12 text-sm text-gray-500">
              <Icon className="size-4 animate-spin" icon="mdi:loading" />
              Loading TLD pricing…
            </div>
          ) : rows.length === 0 ? (
            <div className="flex flex-col items-center gap-3 py-16 text-center">
              <Icon className="size-8 text-gray-400" icon="mdi:table-off" />
              <p className="max-w-md text-sm text-gray-500">
                {debouncedSearch || category !== "all"
                  ? "No extension matches this search."
                  : "The pricing table is empty. Use Import TLDs to load every extension from the IANA root zone with seed pricing you can edit."}
              </p>
              {!debouncedSearch && category === "all" && (
                <Button onPress={() => setImportOpen(true)}>Import TLDs</Button>
              )}
            </div>
          ) : (
            <div
              className={
                "w-full overflow-x-auto " + (fetching ? "opacity-60" : "")
              }
            >
              <table className="w-full min-w-[900px] border-collapse text-left">
                <thead>
                  <tr className="border-b border-gray-200 text-xs font-medium tracking-wide text-gray-500 uppercase dark:border-ink-700">
                    <th className="px-3 py-3">TLD</th>
                    <th className="px-3 py-3">Registration</th>
                    <th className="px-3 py-3">Renewal</th>
                    <th className="px-3 py-3">Transfer</th>
                    <th className="px-3 py-3">Best value</th>
                    <th className="px-3 py-3">Visible</th>
                    <th className="px-3 py-3">Actions</th>
                  </tr>
                </thead>
                <tbody>
                  {rows.map((row) => (
                    <tr
                      key={row.tld}
                      className="border-b border-gray-100 last:border-b-0 hover:bg-gray-50 dark:border-ink-800 dark:hover:bg-ink-800/50"
                    >
                      <td className="px-3 py-3">
                        <div className="flex flex-col gap-1">
                          <span className="font-mono text-sm font-semibold">
                            .{row.unicode || row.tld}
                          </span>
                          <span className="w-fit">
                            <Chip size="sm" variant="soft" color="default">
                              {CATEGORY_LABELS[row.category] || row.category}
                            </Chip>
                          </span>
                        </div>
                      </td>
                      <td className="px-3 py-3">{priceCell(row.registration)}</td>
                      <td className="px-3 py-3">{priceCell(row.renewal)}</td>
                      <td className="px-3 py-3">{priceCell(row.transfer)}</td>
                      <td className="px-3 py-3">
                        <div className="flex flex-col">
                          <span className="text-sm">
                            {registrarName(registrars, row.bestValue?.registrar) || (
                              <span className="text-gray-300">—</span>
                            )}
                          </span>
                          <span className="font-mono text-xs text-gray-500">
                            {formatPrice(row.bestValue?.registration, symbol) ||
                              "—"}{" "}
                            /{" "}
                            {formatPrice(row.bestValue?.renewal, symbol) || "—"}
                          </span>
                        </div>
                      </td>
                      <td className="px-3 py-3">
                        <button
                          type="button"
                          onClick={() => toggleEnabled(row)}
                          className="cursor-pointer"
                          aria-label={
                            row.enabled ? "Hide extension" : "Show extension"
                          }
                        >
                          <span className="w-fit">
                            <Chip
                              size="sm"
                              variant="soft"
                              color={row.enabled ? "success" : "warning"}
                            >
                              {row.enabled ? "✓ Visible" : "✖ Hidden"}
                            </Chip>
                          </span>
                        </button>
                      </td>
                      <td className="px-3 py-3">
                        <div className="flex items-center gap-2">
                          <Button
                            isIconOnly
                            size="sm"
                            variant="tertiary"
                            aria-label={`Edit .${row.tld}`}
                            onPress={() => {
                              setEditRow(row);
                              setEditOpen(true);
                            }}
                          >
                            <Icon className="size-4" icon="gravity-ui:pencil" />
                          </Button>
                          <Button
                            isIconOnly
                            size="sm"
                            variant="danger-soft"
                            aria-label={`Delete .${row.tld}`}
                            onPress={() => {
                              setDeleteTld(row.tld);
                              setDeleteOpen(true);
                            }}
                          >
                            <Icon
                              className="size-4"
                              icon="gravity-ui:trash-bin"
                            />
                          </Button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </Card.Content>

        <Separator />

        <Card.Footer className="flex flex-wrap items-center justify-between gap-3">
          <span className="font-mono text-xs text-gray-500">
            {total.toLocaleString()} extension{total === 1 ? "" : "s"} · page{" "}
            {page} of {totalPages}
          </span>

          <div className="flex items-center gap-2">
            <Button
              size="sm"
              variant="tertiary"
              isDisabled={page <= 1}
              onPress={() => setPage((p) => Math.max(1, p - 1))}
            >
              Previous
            </Button>
            <Button
              size="sm"
              variant="tertiary"
              isDisabled={page >= totalPages}
              onPress={() => setPage((p) => Math.min(totalPages, p + 1))}
            >
              Next
            </Button>
          </div>
        </Card.Footer>
      </Card>
    </AdminLayout>
  );
}
