// src/components/backlink/reservoir-container.tsx
"use client";

import type {
  ColumnDef,
  ColumnFiltersState,
  PaginationState,
  RowSelectionState,
  VisibilityState,
} from "@tanstack/react-table";
import { CrosshairIcon } from "lucide-react";
import { useRouter } from "next/navigation";
import { parseAsString, useQueryState } from "nuqs";
import { useCallback, useMemo, useState } from "react";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { DataTable } from "@/components/ui/data-table";
import { ToolbarMetaRow, ToolbarPanel } from "@/components/ui/design-toolbar";
import { addSourcesToSiteAction } from "@/lib/backlink/actions";
import {
  fetchDomainRatingsChunkAction,
  fetchStaleDomainsAction,
} from "@/lib/backlink/dr-actions";
import {
  getAllOrgsSourcesAction,
  setSourceGlobalAction,
} from "@/lib/backlink/global-actions";
import type { LinkSource } from "@/lib/backlink/types";
import { useActiveSite } from "@/lib/keywords/site-context";
import { cn } from "@/lib/utils";
import { columns, DEFAULT_COLUMN_VISIBILITY } from "./columns";
import {
  ActiveFilterChips,
  ReservoirActions,
  ReservoirToolbar,
} from "./reservoir-toolbar";

/** God-mode all-orgs row: a reservoir source plus its owning org's name. */
type AllOrgsRow = LinkSource & { orgName: string };

/**
 * Read-only column subset for the « Toutes les orgs » view: no selection,
 * no footprint (org-scoped meta), no themes/tags/flags noise.
 */
const ALL_ORGS_COLUMN_IDS = new Set([
  "platform",
  "kind",
  "da",
  "linkType",
  "effort",
  "language",
]);

const orgColumn: ColumnDef<AllOrgsRow> = {
  id: "org",
  header: "Org",
  enableGlobalFilter: false,
  accessorFn: (s) => s.orgName,
  cell: ({ row }) => <Badge variant="outline">{row.original.orgName}</Badge>,
};

const allOrgsColumns: ColumnDef<AllOrgsRow>[] = [
  orgColumn,
  ...(columns.filter((c) => {
    const id = c.id ?? ("accessorKey" in c ? (c.accessorKey as string) : "");
    return ALL_ORGS_COLUMN_IDS.has(id);
  }) as ColumnDef<AllOrgsRow>[]),
];

interface Props {
  sources: LinkSource[];
  initialFootprint: Record<string, string[]>;
  isSuperAdmin: boolean;
}

export function BacklinkReservoirContainer({
  sources,
  initialFootprint,
  isSuperAdmin,
}: Props) {
  const router = useRouter();
  const { sites, activeSite } = useActiveSite();
  const [footprint, setFootprint] = useState(initialFootprint);
  // God-mode: local 🌐 overrides layered over the server rows so the toggle is
  // instant; `revalidatePath` then refreshes `sources` with the same values.
  const [globalOverrides, setGlobalOverrides] = useState<
    Record<string, boolean>
  >({});
  // God-mode: « Toutes les orgs » read-only view (fetched once, kept in state).
  const [allOrgs, setAllOrgs] = useState(false);
  const [allOrgsRows, setAllOrgsRows] = useState<AllOrgsRow[] | null>(null);
  const [allOrgsBusy, setAllOrgsBusy] = useState(false);
  const [drBusy, setDrBusy] = useState(false);
  const [drProgress, setDrProgress] = useState<{
    done: number;
    total: number;
  } | null>(null);

  const toggleGlobal = useCallback(async (s: LinkSource) => {
    const next = !s.global;
    try {
      const res = await setSourceGlobalAction(s.id, next);
      if (!res.ok) {
        toast.error("Échec de la mise à jour du catalogue global");
        return;
      }
      setGlobalOverrides((prev) => ({ ...prev, [s.id]: next }));
      toast.success(
        next
          ? `${s.platform} ajouté au catalogue global`
          : `${s.platform} retiré du catalogue global`,
      );
    } catch {
      toast.error("Échec de la mise à jour du catalogue global");
    }
  }, []);

  // Super-admin-only 🌐 column, appended in the container so the shared
  // columns stay untouched for normal users.
  const globalColumn = useMemo<ColumnDef<LinkSource>>(
    () => ({
      id: "global",
      header: "🌐",
      enableGlobalFilter: false,
      accessorFn: (s) => (s.global ? 1 : 0),
      meta: { align: "center" },
      cell: ({ row }) => (
        <Button
          size="icon"
          variant="ghost"
          className={cn("size-7", row.original.global ? "" : "opacity-30")}
          aria-pressed={row.original.global}
          aria-label={`${row.original.platform} — catalogue global : ${
            row.original.global ? "oui" : "non"
          }`}
          title={
            row.original.global
              ? "Dans le catalogue global (cliquer pour retirer)"
              : "Hors catalogue (cliquer pour ajouter)"
          }
          onClick={(e) => {
            e.stopPropagation();
            void toggleGlobal(row.original);
          }}
        >
          🌐
        </Button>
      ),
    }),
    [toggleGlobal],
  );

  const tableColumns = useMemo(
    () => (isSuperAdmin ? [...columns, globalColumn] : columns),
    [isSuperAdmin, globalColumn],
  );

  const rows = useMemo(
    () =>
      sources.map((s) =>
        globalOverrides[s.id] !== undefined &&
        globalOverrides[s.id] !== s.global
          ? { ...s, global: globalOverrides[s.id] }
          : s,
      ),
    [sources, globalOverrides],
  );

  async function toggleAllOrgs() {
    if (allOrgs) {
      setAllOrgs(false);
      return;
    }
    setAllOrgs(true);
    if (allOrgsRows !== null || allOrgsBusy) return;
    setAllOrgsBusy(true);
    try {
      setAllOrgsRows(await getAllOrgsSourcesAction());
    } catch {
      toast.error("Échec du chargement des sources de toutes les orgs");
      setAllOrgs(false);
    } finally {
      setAllOrgsBusy(false);
    }
  }

  async function refreshDr() {
    setDrBusy(true);
    try {
      const domains = await fetchStaleDomainsAction();
      if (domains.length === 0) {
        toast.info("DR déjà à jour");
        return;
      }
      setDrProgress({ done: 0, total: domains.length });
      const CHUNK = 25;
      let updated = 0;
      for (let i = 0; i < domains.length; i += CHUNK) {
        const slice = domains.slice(i, i + CHUNK);
        const res = await fetchDomainRatingsChunkAction(slice);
        updated += res.updated;
        setDrProgress({
          done: Math.min(i + CHUNK, domains.length),
          total: domains.length,
        });
        if (res.rateLimited) {
          toast.error("Limite Ahrefs atteinte — réessaie plus tard");
          break;
        }
      }
      toast.success(`${updated} DR mis à jour`);
      router.refresh();
    } catch {
      toast.error("Échec du rafraîchissement DR");
    } finally {
      setDrBusy(false);
      setDrProgress(null);
    }
  }

  // URL-synced filters (deep-linkable). Each defaults to "" and drops its key
  // when empty so a pristine reservoir keeps a clean URL. `kind`/`linkType`/
  // `effort` are TanStack facet filters (stored as `[value]`) projected onto
  // dedicated query keys; the rest of `columnFilters` (the DA range) stays local.
  const facetOpts = parseAsString
    .withDefault("")
    .withOptions({ clearOnDefault: true });
  const [search, setSearch] = useQueryState("q", facetOpts);
  const [kind, setKind] = useQueryState("kind", facetOpts);
  const [linkType, setLinkType] = useQueryState("linkType", facetOpts);
  const [effort, setEffort] = useQueryState("effort", facetOpts);
  // Non-facet filters (DA range) kept local; facets come from the URL.
  const [localFilters, setLocalFilters] = useState<ColumnFiltersState>([]);

  const FACET_KEYS = ["kind", "linkType", "effort"] as const;
  const facetSetters: Record<
    (typeof FACET_KEYS)[number],
    (v: string | null) => void
  > = { kind: setKind, linkType: setLinkType, effort: setEffort };

  // Compose the TanStack filter state the bar expects from URL facets + local.
  const columnFilters = useMemo<ColumnFiltersState>(() => {
    const facets: ColumnFiltersState = [];
    if (kind) facets.push({ id: "kind", value: [kind] });
    if (linkType) facets.push({ id: "linkType", value: [linkType] });
    if (effort) facets.push({ id: "effort", value: [effort] });
    return [...facets, ...localFilters];
  }, [kind, linkType, effort, localFilters]);

  // Split incoming filter updates: facet values go to the URL, everything else
  // stays local. Keeps the filters bar's prop contract byte-identical.
  function setColumnFilters(next: ColumnFiltersState) {
    for (const key of FACET_KEYS) {
      const v = (
        next.find((f) => f.id === key)?.value as string[] | undefined
      )?.[0];
      facetSetters[key](v ?? null);
    }
    setLocalFilters(next.filter((f) => !FACET_KEYS.includes(f.id as never)));
  }
  const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(
    DEFAULT_COLUMN_VISIBILITY,
  );
  const [rowSelection, setRowSelection] = useState<RowSelectionState>({});

  // Pagination is owned here so the meta row (above the table) can render the
  // « 50 / page · Précédent · Page x/y · Suivant » controls (design ELEVA-79).
  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: 0,
    pageSize: 50,
  });
  const [filteredCount, setFilteredCount] = useState(sources.length);
  const handleFilteredRows = useCallback((visible: LinkSource[]) => {
    setFilteredCount(visible.length);
  }, []);
  const pageCount = Math.max(1, Math.ceil(filteredCount / pagination.pageSize));

  const selectedIds = useMemo(
    () =>
      Object.entries(rowSelection)
        .filter(([, v]) => v)
        .map(([id]) => id),
    [rowSelection],
  );

  const reservoirSites = useMemo(
    () => sites.map((s) => ({ id: s.id, name: s.name })),
    [sites],
  );

  // Optimistic footprint update + persisted backlink prospects for the active
  // site. Snapshot the previous footprint so we can roll back on failure.
  async function addToActiveSite() {
    if (!activeSite || selectedIds.length === 0) return;
    const ids = selectedIds;
    const siteId = activeSite.id;
    let prevFootprint: Record<string, string[]> | undefined;
    setFootprint((prev) => {
      prevFootprint = prev;
      const next = { ...prev };
      for (const id of ids) {
        const cur = next[id] ?? [];
        if (!cur.includes(siteId)) next[id] = [...cur, siteId];
      }
      return next;
    });
    setRowSelection({});
    try {
      await addSourcesToSiteAction(ids, siteId);
      toast.success(
        `${ids.length} source${ids.length > 1 ? "s" : ""} ajoutée${
          ids.length > 1 ? "s" : ""
        } au site`,
      );
    } catch {
      if (prevFootprint) setFootprint(prevFootprint);
      toast.error("Échec de l'ajout au site");
    }
  }

  // God-mode « Toutes les orgs »: read-only cross-org table, no mutating UI.
  if (allOrgs) {
    return (
      <div className="space-y-3 p-4">
        <div className="flex items-center justify-between gap-2">
          <span className="text-muted-foreground text-sm">
            Vue god-mode — sources de toutes les organisations (lecture seule)
          </span>
          <Button variant="default" size="sm" onClick={toggleAllOrgs}>
            Toutes les orgs
          </Button>
        </div>
        {allOrgsBusy ? (
          <p className="text-muted-foreground text-sm">Chargement…</p>
        ) : (
          <DataTable
            columns={allOrgsColumns}
            data={allOrgsRows ?? []}
            getRowId={(s) => s.id}
            caption="Sources de liens de toutes les organisations"
            pageSize={50}
            pageSizeOptions={[20, 50, 100, 500]}
          />
        )}
      </div>
    );
  }

  return (
    <div className="p-4">
      {/* Design panel: toolbar / chips / meta / selection / table. */}
      <ToolbarPanel>
        <ReservoirToolbar
          search={search}
          onSearch={setSearch}
          columnFilters={columnFilters}
          onColumnFilters={setColumnFilters}
          columnVisibility={columnVisibility}
          onColumnVisibility={setColumnVisibility}
          actions={
            <ReservoirActions
              isSuperAdmin={isSuperAdmin}
              drBusy={drBusy}
              drProgress={drProgress}
              onRefreshDr={refreshDr}
              onShowAllOrgs={toggleAllOrgs}
            />
          }
        />
        <ActiveFilterChips
          columnFilters={columnFilters}
          onColumnFilters={setColumnFilters}
        />
        <ToolbarMetaRow
          resultCount={filteredCount}
          filterCount={columnFilters.length}
          pagination={{
            pageIndex: pagination.pageIndex,
            pageCount,
            pageSize: pagination.pageSize,
            pageSizeOptions: [20, 50, 100, 500],
            onPageSizeChange: (n) =>
              setPagination({ pageIndex: 0, pageSize: n }),
            onPrevious: () =>
              setPagination((p) => ({
                ...p,
                pageIndex: Math.max(0, p.pageIndex - 1),
              })),
            onNext: () =>
              setPagination((p) => ({
                ...p,
                pageIndex: Math.min(pageCount - 1, p.pageIndex + 1),
              })),
          }}
        />

        {selectedIds.length > 0 ? (
          <div className="flex items-center gap-3 border-t bg-muted/40 px-4 py-2.5">
            <span className="font-medium text-sm">
              {selectedIds.length} sélectionnée
              {selectedIds.length > 1 ? "s" : ""}
            </span>
            <Button
              variant="outline"
              size="sm"
              onClick={addToActiveSite}
              disabled={!activeSite}
            >
              <CrosshairIcon className="size-4" aria-hidden />
              Ajouter à {activeSite?.name ?? "—"}
            </Button>
            <button
              type="button"
              onClick={() => setRowSelection({})}
              className="text-muted-foreground text-sm hover:text-foreground"
            >
              Effacer
            </button>
          </div>
        ) : null}

        <DataTable
          columns={tableColumns}
          data={rows}
          getRowId={(s) => s.id}
          globalFilter={search}
          columnFilters={columnFilters}
          columnVisibility={columnVisibility}
          rowSelection={rowSelection}
          onRowSelectionChange={setRowSelection}
          meta={{ footprint, activeSiteId: activeSite?.id, reservoirSites }}
          caption="Reservoir global de sources de liens"
          pageSize={50}
          pagination={pagination}
          onPaginationChange={setPagination}
          hidePagination
          onFilteredRowsChange={handleFilteredRows}
          containerClassName="rounded-none border-0 border-t"
        />
      </ToolbarPanel>
    </div>
  );
}
