// src/components/backlink/columns.tsx
"use client";

import type { ColumnDef, RowData } from "@tanstack/react-table";
import { ExternalLinkIcon } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import type { Effort, LinkSource } from "@/lib/backlink/types";
import { cn } from "@/lib/utils";
import { DrBadge } from "./dr-badge";
import {
  EffortBadge,
  FlagIcons,
  KindBadge,
  LanguageFlag,
  LinkTypeBadge,
} from "./source-badges";

declare module "@tanstack/react-table" {
  interface TableMeta<TData extends RowData> {
    /** sourceId -> siteIds targeting it. */
    footprint?: Record<string, string[]>;
    activeSiteId?: string;
    reservoirSites?: { id: string; name: string }[];
  }
}

/** Displayed domain strength: cached Ahrefs DR, else the manual DA. */
const resolvedDr = (s: LinkSource): number | null => s.dr ?? s.da;

const arrIncludesSome = (
  row: { getValue: (id: string) => unknown },
  columnId: string,
  filterValue: string[],
) => {
  if (!filterValue?.length) return true;
  const cell = row.getValue(columnId);
  if (Array.isArray(cell)) return cell.some((v) => filterValue.includes(v));
  return filterValue.includes(cell as string);
};

/** DR range filter; null DR is excluded as soon as any bound is set. */
const daRange = (
  row: { getValue: (id: string) => unknown },
  columnId: string,
  [min, max]: [number | undefined, number | undefined],
) => {
  const v = row.getValue(columnId) as number | null;
  if (min == null && max == null) return true;
  if (v == null) return false;
  if (min != null && v < min) return false;
  if (max != null && v > max) return false;
  return true;
};

/** Effort sort: by difficulty (low → medium → high), not alphabetical. */
const EFFORT_RANK: Record<Effort, number> = { low: 0, medium: 1, high: 2 };

/** DR sort: nulls grouped at the bottom of the natural ascending order. */
const sortDa = (a: { original: LinkSource }, b: { original: LinkSource }) => {
  const x = resolvedDr(a.original) ?? Number.NEGATIVE_INFINITY;
  const y = resolvedDr(b.original) ?? Number.NEGATIVE_INFINITY;
  return x - y;
};

export const TOGGLEABLE_COLUMNS: { id: string; label: string }[] = [
  { id: "kind", label: "Kind" },
  { id: "da", label: "DR" },
  { id: "linkType", label: "Link Type" },
  { id: "effort", label: "Effort" },
  { id: "footprint", label: "Ciblé" },
  { id: "language", label: "Langue" },
  { id: "themes", label: "Thèmes" },
  { id: "tags", label: "Tags" },
  { id: "flags", label: "Flags" },
];

/** Thèmes / tags hidden by default (empty in this slice). */
export const DEFAULT_COLUMN_VISIBILITY = {
  themes: false,
  tags: false,
};

const baseColumns: ColumnDef<LinkSource>[] = [
  {
    id: "select",
    enableGlobalFilter: false,
    enableSorting: false,
    header: ({ table }) => (
      <Checkbox
        checked={
          table.getIsAllRowsSelected() ||
          (table.getIsSomeRowsSelected() && "indeterminate")
        }
        onCheckedChange={(v) => table.toggleAllRowsSelected(!!v)}
        aria-label="Tout sélectionner"
      />
    ),
    cell: ({ row }) => (
      <Checkbox
        checked={row.getIsSelected()}
        onCheckedChange={(v) => row.toggleSelected(!!v)}
        onClick={(e) => e.stopPropagation()}
        aria-label={`Sélectionner ${row.original.platform}`}
      />
    ),
  },
  {
    id: "platform",
    accessorFn: (s) => `${s.platform} ${s.domainNorm}`,
    header: "Platform",
    cell: ({ row }) => (
      <div className="flex max-w-[13rem] flex-col">
        <span className="truncate font-medium">{row.original.platform}</span>
        <a
          href={row.original.url}
          target="_blank"
          rel="noopener noreferrer"
          onClick={(e) => e.stopPropagation()}
          className="flex items-center gap-1 text-muted-foreground text-xs hover:text-foreground"
        >
          <span className="truncate">{row.original.domainNorm}</span>
          <ExternalLinkIcon className="size-3 shrink-0" aria-hidden />
        </a>
      </div>
    ),
  },
  {
    accessorKey: "kind",
    header: "Kind",
    enableGlobalFilter: false,
    filterFn: arrIncludesSome,
    cell: ({ row }) => <KindBadge kind={row.original.kind} />,
  },
  {
    id: "da",
    accessorFn: (s) => resolvedDr(s),
    header: "DR",
    enableGlobalFilter: false,
    filterFn: daRange,
    sortingFn: sortDa,
    cell: ({ row }) => <DrBadge value={resolvedDr(row.original)} />,
  },
  {
    accessorKey: "linkType",
    header: "Link Type",
    enableGlobalFilter: false,
    filterFn: arrIncludesSome,
    cell: ({ row }) => <LinkTypeBadge value={row.original.linkType} />,
  },
  {
    accessorKey: "effort",
    header: "Effort",
    enableGlobalFilter: false,
    filterFn: arrIncludesSome,
    sortingFn: (a, b) =>
      EFFORT_RANK[a.original.effort] - EFFORT_RANK[b.original.effort],
    cell: ({ row }) => <EffortBadge value={row.original.effort} />,
  },
  {
    id: "footprint",
    header: "Ciblé",
    enableGlobalFilter: false,
    enableSorting: false,
    cell: ({ row, table }) => {
      const fp = table.options.meta?.footprint?.[row.original.id] ?? [];
      if (fp.length === 0)
        return <span className="text-muted-foreground">—</span>;
      const sites = table.options.meta?.reservoirSites ?? [];
      const active = table.options.meta?.activeSiteId;
      const nameOf = (id: string) => sites.find((s) => s.id === id)?.name ?? id;
      return (
        <div className="flex flex-wrap justify-center gap-1">
          {fp.map((id) => (
            <span
              key={id}
              title={nameOf(id)}
              className={cn(
                "inline-flex items-center rounded-md border px-1.5 py-0.5 font-semibold text-xs",
                id === active
                  ? "border-primary/30 bg-primary/10 text-primary"
                  : "border-border bg-muted text-muted-foreground",
              )}
            >
              {nameOf(id).slice(0, 2).toUpperCase()}
            </span>
          ))}
        </div>
      );
    },
  },
  {
    accessorKey: "language",
    header: "Langue",
    enableGlobalFilter: false,
    filterFn: arrIncludesSome,
    cell: ({ row }) => <LanguageFlag code={row.original.language} />,
  },
  {
    id: "themes",
    header: "Thèmes",
    enableGlobalFilter: false,
    enableSorting: false,
    cell: ({ row }) =>
      row.original.themes.length ? (
        <span className="text-xs">{row.original.themes.join(", ")}</span>
      ) : (
        <span className="text-muted-foreground">—</span>
      ),
  },
  {
    id: "tags",
    header: "Tags",
    enableGlobalFilter: false,
    enableSorting: false,
    cell: ({ row }) =>
      row.original.tags.length ? (
        <span className="text-xs">{row.original.tags.join(", ")}</span>
      ) : (
        <span className="text-muted-foreground">—</span>
      ),
  },
  {
    id: "flags",
    header: "Flags",
    enableGlobalFilter: false,
    enableSorting: false,
    cell: ({ row }) => <FlagIcons flags={row.original.flags} />,
  },
];

/** Every column is centered except Platform (kept left-aligned). */
const colKey = (c: ColumnDef<LinkSource>): string | undefined =>
  c.id ?? ("accessorKey" in c ? (c.accessorKey as string) : undefined);

export const columns: ColumnDef<LinkSource>[] = baseColumns.map((c) =>
  colKey(c) === "platform"
    ? c
    : { ...c, meta: { ...c.meta, align: "center" as const } },
);
