// src/components/content/content-board.tsx
"use client";

import {
  DndContext,
  type DragEndEvent,
  PointerSensor,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import type {
  ColumnFiltersState,
  PaginationState,
} from "@tanstack/react-table";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { ToolbarMetaRow, ToolbarPanel } from "@/components/ui/design-toolbar";
import { Skeleton } from "@/components/ui/skeleton";
import {
  getContentExportRowsAction,
  getContentItemsForSiteAction,
  updateContentStatusAction,
} from "@/lib/content/actions";
import { groupByStatus } from "@/lib/content/board";
import { buildContentCsv } from "@/lib/content/csv";
import type { ContentItem } from "@/lib/content/types";
import { CONTENT_STATUSES } from "@/lib/content/types";
import type { ContentStatus } from "@/lib/db/domain-schema";
import { useActiveSite } from "@/lib/keywords/site-context";
import { ContentCardSheet } from "./content-card-sheet";
import { ContentColumn } from "./content-column";
import { ContentTable } from "./content-table";
import {
  type BoardView,
  ContentFilterChips,
  ContentToolbar,
  filterContentItems,
} from "./content-toolbar";
import { ImportCsvDialog } from "./import-csv-dialog";
import { NewContentDialog } from "./new-content-dialog";

const STATUS_SET = new Set<string>(CONTENT_STATUSES);

const VIEW_STORAGE_KEY = "seo-insight:content-view";

function readStoredView(): BoardView | null {
  if (typeof window === "undefined") return null;
  try {
    const raw = window.localStorage.getItem(VIEW_STORAGE_KEY);
    return raw === "board" || raw === "table" ? raw : null;
  } catch {
    return null;
  }
}

export function ContentBoard({
  initialItems,
  initialSiteId,
}: {
  initialItems: ContentItem[];
  initialSiteId: string;
}) {
  const { activeSiteId } = useActiveSite();
  const [items, setItems] = useState<ContentItem[]>(initialItems);
  const [loading, setLoading] = useState(false);
  const [open, setOpen] = useState<ContentItem | null>(null);
  const [newOpen, setNewOpen] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [view, setView] = useState<BoardView>("table");
  // Pure client-side filtering (ELEVA-89): search over titre / mot-clé plus
  // statut / assigné / langue facets — applied to both kanban and liste.
  const [search, setSearch] = useState("");
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
  // 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,
  });
  // The server already provided items for this site — track it so we never
  // refetch on mount. Firing a read server action on mount triggers an implicit
  // route revalidation that races and deadlocks the next client navigation.
  const loadedSite = useRef(initialSiteId);
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
  );

  const load = useCallback(async () => {
    setLoading(true);
    try {
      setItems(await getContentItemsForSiteAction(activeSiteId));
    } finally {
      setLoading(false);
    }
  }, [activeSiteId]);

  // Refetch + confirm after a content item is created. The silent background
  // load (mount / site switch) stays toast-free.
  const onCreated = useCallback(async () => {
    await load();
    toast.success("Article créé");
  }, [load]);

  useEffect(() => {
    // Only refetch when the site actually changes — never on mount for the
    // server-provided site.
    if (activeSiteId === loadedSite.current) return;
    loadedSite.current = activeSiteId;
    void load().catch(() => setLoading(false));
  }, [activeSiteId, load]);

  // Hydratation après montage uniquement → pas de mismatch SSR (cf. use-checklist-state).
  useEffect(() => {
    const stored = readStoredView();
    if (stored) setView(stored);
  }, []);

  function switchView(v: BoardView) {
    setView(v);
    try {
      window.localStorage.setItem(VIEW_STORAGE_KEY, v);
    } catch {
      // quota / mode privé : on garde l'état en mémoire.
    }
  }

  // Filter changes reset the page so the liste never lands on an empty page.
  function handleSearch(v: string) {
    setSearch(v);
    setPagination((p) => ({ ...p, pageIndex: 0 }));
  }
  function handleColumnFilters(next: ColumnFiltersState) {
    setColumnFilters(next);
    setPagination((p) => ({ ...p, pageIndex: 0 }));
  }

  async function exportCsv() {
    const rows = await getContentExportRowsAction(activeSiteId);
    if (rows.length === 0) {
      toast.error("Aucun contenu à exporter");
      return;
    }
    // BOM pour qu'Excel ouvre le fichier en UTF-8.
    const blob = new Blob(["﻿", buildContentCsv(rows)], {
      type: "text/csv;charset=utf-8",
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `contenu-${activeSiteId}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  }

  function onDragEnd(e: DragEndEvent) {
    const id = String(e.active.id);
    const over = e.over ? String(e.over.id) : null;
    if (!over || !STATUS_SET.has(over)) return;
    const status = over as ContentStatus;
    const current = items.find((i) => i.id === id);
    if (!current || current.status === status) return;
    const prev = items;
    setItems((xs) => xs.map((i) => (i.id === id ? { ...i, status } : i)));
    updateContentStatusAction(id, status).catch(() => {
      setItems(prev);
      toast.error("Échec du changement de statut");
    });
  }

  const assignees = useMemo(
    () =>
      [
        ...new Set(
          items.map((i) => i.assignee).filter((a): a is string => !!a),
        ),
      ].sort(),
    [items],
  );
  const languages = useMemo(
    () => [...new Set(items.map((i) => i.lang).filter(Boolean))].sort(),
    [items],
  );

  const filteredItems = useMemo(
    () => filterContentItems(items, search, columnFilters),
    [items, search, columnFilters],
  );

  const pageCount = Math.max(
    1,
    Math.ceil(filteredItems.length / pagination.pageSize),
  );

  const nowIso = new Date().toISOString();
  const columns = groupByStatus(filteredItems);

  return (
    <div className="p-4">
      {/* Design panel: toolbar / chips / (meta + liste | kanban). */}
      <ToolbarPanel>
        <ContentToolbar
          search={search}
          onSearch={handleSearch}
          columnFilters={columnFilters}
          onColumnFilters={handleColumnFilters}
          assignees={assignees}
          languages={languages}
          view={view}
          onViewChange={switchView}
          onExportCsv={() => void exportCsv()}
          onImportCsv={() => setImportOpen(true)}
          onNewContent={() => setNewOpen(true)}
        />
        <ContentFilterChips
          columnFilters={columnFilters}
          onColumnFilters={handleColumnFilters}
        />
        {view === "table" ? (
          <ToolbarMetaRow
            resultCount={filteredItems.length}
            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),
                })),
            }}
          />
        ) : null}
        {loading ? (
          <div className="border-t p-4">
            <Skeleton className="h-64 w-full" />
          </div>
        ) : view === "table" ? (
          <ContentTable
            items={filteredItems}
            onOpen={setOpen}
            pagination={pagination}
            onPaginationChange={setPagination}
          />
        ) : (
          <DndContext sensors={sensors} onDragEnd={onDragEnd}>
            <div className="flex gap-3 overflow-x-auto p-4">
              {columns.map((c) => (
                <ContentColumn
                  key={c.status}
                  status={c.status}
                  items={c.items}
                  nowIso={nowIso}
                  onOpen={setOpen}
                />
              ))}
            </div>
          </DndContext>
        )}
      </ToolbarPanel>
      <ImportCsvDialog
        siteId={activeSiteId}
        open={importOpen}
        onOpenChange={setImportOpen}
        onImported={load}
      />
      <NewContentDialog
        open={newOpen}
        onOpenChange={setNewOpen}
        siteId={activeSiteId}
        onCreated={onCreated}
      />
      <ContentCardSheet
        item={open}
        open={open !== null}
        onOpenChange={(o) => {
          if (!o) setOpen(null);
        }}
        onSaved={load}
      />
    </div>
  );
}
