"use client";

import { useEffect } from "react";

type Direction = "asc" | "desc" | null;
type GridState = {
  table: HTMLTableElement; toolbar: HTMLDivElement; search: HTMLInputElement; count: HTMLSpanElement;
  pageLabel: HTMLSpanElement; previous: HTMLButtonElement; next: HTMLButtonElement; pageSize: HTMLSelectElement;
  density: HTMLButtonElement; query: string; page: number; limit: number; sortColumn: number; direction: Direction;
  originalOrder: Map<HTMLTableRowElement, number>; disposers: Array<() => void>;
};

const PRINT_SELECTOR = [
  "[data-datagrid='off']", ".print-order", ".print-report", ".print-schedule", ".print-approvals", ".print-intelligent",
  ".print-bank-history", ".print-history-state", ".print-remittance-advice", ".statement-print", ".aging-detail-print",
  ".collections-report-print", ".purchase-print-document", ".work-order-document", ".fuel-print-document",
  ".driver-print-document", ".vehicle-print-document", ".fuel-report-document", ".fuel-filtered-history-document",
  ".consumption-day-document", ".consumption-report-document", ".reliability-report-document",
  ".tire-report-document", ".battery-report-document",
].join(",");

const cleanText = (value: string) => value.replace(/\s+/g, " ").trim();

function sortableValue(value: string) {
  const text = cleanText(value);
  const isoDate = text.match(/^(\d{4})-(\d{2})-(\d{2})/);
  if (isoDate) return { kind: "number" as const, value: Date.UTC(Number(isoDate[1]), Number(isoDate[2]) - 1, Number(isoDate[3])) };
  const frenchDate = text.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})/);
  if (frenchDate) return { kind: "number" as const, value: Date.UTC(Number(frenchDate[3]), Number(frenchDate[2]) - 1, Number(frenchDate[1])) };
  const numberText = text.replace(/[^\d,.-]/g, "").replace(/\.(?=\d{3}(?:\D|$))/g, "").replace(",", ".");
  if (numberText && /^-?\d+(?:\.\d+)?$/.test(numberText)) return { kind: "number" as const, value: Number(numberText) };
  return { kind: "text" as const, value: text.toLocaleLowerCase("fr") };
}

const bodyRows = (table: HTMLTableElement) => table.tBodies[0] ? Array.from(table.tBodies[0].rows) : [];

function createButton(label: string, className: string) {
  const button = document.createElement("button"); button.type = "button"; button.className = className; button.textContent = label; return button;
}

function refresh(state: GridState) {
  const rows = bodyRows(state.table);
  rows.forEach((row) => { if (!state.originalOrder.has(row)) state.originalOrder.set(row, state.originalOrder.size); });
  const orderedRows = [...rows];
  if (state.direction && state.sortColumn >= 0 && state.table.tBodies[0]) {
    orderedRows.sort((left, right) => {
      const leftValue = sortableValue(left.cells[state.sortColumn]?.dataset.sortValue || left.cells[state.sortColumn]?.textContent || "");
      const rightValue = sortableValue(right.cells[state.sortColumn]?.dataset.sortValue || right.cells[state.sortColumn]?.textContent || "");
      const comparison = leftValue.kind === "number" && rightValue.kind === "number"
        ? Number(leftValue.value) - Number(rightValue.value)
        : String(leftValue.value).localeCompare(String(rightValue.value), "fr", { numeric: true, sensitivity: "base" });
      return state.direction === "asc" ? comparison : -comparison;
    });
  } else {
    orderedRows.sort((left, right) => (state.originalOrder.get(left) ?? 0) - (state.originalOrder.get(right) ?? 0));
  }
  if (state.table.tBodies[0] && orderedRows.some((row, index) => rows[index] !== row)) orderedRows.forEach((row) => state.table.tBodies[0].appendChild(row));
  const visibleOrder = bodyRows(state.table);
  const matching = visibleOrder.filter((row) => !state.query || cleanText(row.textContent || "").toLocaleLowerCase("fr").includes(state.query));
  const pageCount = Math.max(1, state.limit ? Math.ceil(matching.length / state.limit) : 1);
  state.page = Math.min(state.page, pageCount - 1);
  const start = state.limit ? state.page * state.limit : 0;
  const end = state.limit ? start + state.limit : matching.length;
  const matchingSet = new Set(matching.slice(start, end));
  visibleOrder.forEach((row) => { row.hidden = !matchingSet.has(row); });
  state.table.setAttribute("aria-rowcount", String(matching.length));
  state.count.textContent = `${matching.length} ligne${matching.length > 1 ? "s" : ""}`;
  state.pageLabel.textContent = matching.length ? `${start + 1}–${Math.min(end, matching.length)} / ${matching.length}` : "0 / 0";
  state.previous.disabled = state.page === 0; state.next.disabled = state.page >= pageCount - 1;
}

function enhance(table: HTMLTableElement): GridState | null {
  if (table.dataset.moventraGrid === "ready" || table.closest(PRINT_SELECTOR) || !table.tHead || !table.tBodies[0]) return null;
  table.dataset.moventraGrid = "ready"; table.classList.add("moventra-datagrid", "is-compact"); table.setAttribute("role", "grid");
  const toolbar = document.createElement("div"); toolbar.className = "moventra-datagrid-toolbar"; toolbar.setAttribute("role", "group"); toolbar.setAttribute("aria-label", "Outils du tableau");
  const searchWrap = document.createElement("label"); searchWrap.className = "moventra-datagrid-search";
  const searchIcon = document.createElement("span"); searchIcon.textContent = "⌕";
  const search = document.createElement("input"); search.type = "search"; search.placeholder = "Rechercher dans le tableau…"; search.setAttribute("aria-label", "Rechercher dans ce tableau");
  searchWrap.append(searchIcon, search);
  const count = document.createElement("span"); count.className = "moventra-datagrid-count";
  const controls = document.createElement("div"); controls.className = "moventra-datagrid-controls";
  const density = createButton("Vue confortable", "moventra-datagrid-density"); density.setAttribute("aria-pressed", "true");
  const pageSize = document.createElement("select"); pageSize.setAttribute("aria-label", "Nombre de lignes par page");
  [["15", "15 lignes"], ["30", "30 lignes"], ["50", "50 lignes"], ["0", "Toutes"]].forEach(([value, label]) => { const option = document.createElement("option"); option.value = value; option.textContent = label; pageSize.appendChild(option); });
  const previous = createButton("‹", "moventra-datagrid-page"); previous.setAttribute("aria-label", "Page précédente");
  const pageLabel = document.createElement("span"); pageLabel.className = "moventra-datagrid-page-label";
  const next = createButton("›", "moventra-datagrid-page"); next.setAttribute("aria-label", "Page suivante");
  controls.append(density, pageSize, previous, pageLabel, next); toolbar.append(searchWrap, count, controls);
  table.parentElement?.insertBefore(toolbar, table); table.parentElement?.classList.add("moventra-datagrid-host");
  const state: GridState = { table, toolbar, search, count, pageLabel, previous, next, pageSize, density, query: "", page: 0, limit: 15, sortColumn: -1, direction: null, originalOrder: new Map(), disposers: [] };
  const selectRow = (row: HTMLTableRowElement) => {
    bodyRows(table).forEach(candidate => { candidate.classList.toggle("is-selected", candidate === row); candidate.setAttribute("aria-selected", String(candidate === row)); });
  };
  bodyRows(table).forEach((row, index) => {
    state.originalOrder.set(row, index); row.tabIndex = 0; row.setAttribute("aria-selected", "false");
    const click = (event: MouseEvent) => { if (!(event.target instanceof HTMLElement) || !event.target.closest("button,a,input,select,textarea,label")) selectRow(row); };
    const key = (event: KeyboardEvent) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); selectRow(row); } };
    row.addEventListener("click", click); row.addEventListener("keydown", key);
    state.disposers.push(() => { row.removeEventListener("click", click); row.removeEventListener("keydown", key); });
  });
  Array.from(table.tHead.rows[table.tHead.rows.length - 1]?.cells || []).forEach((header, index) => {
    const label = cleanText(header.textContent || "");
    if (!label || header.querySelector("input,button,select") || /^(action|actions|sélection)$/i.test(label)) return;
    header.classList.add("moventra-sortable"); header.tabIndex = 0; header.setAttribute("aria-sort", "none"); header.title = `Trier par ${label}`;
    const indicator = document.createElement("span"); indicator.className = "moventra-sort-indicator"; indicator.setAttribute("aria-hidden", "true"); indicator.textContent = "↕"; header.appendChild(indicator);
    const sort = () => {
      const siblingHeaders = header.parentElement instanceof HTMLTableRowElement ? Array.from(header.parentElement.cells) : [];
      siblingHeaders.forEach((cell) => cell.setAttribute("aria-sort", "none"));
      state.direction = state.sortColumn !== index ? "asc" : state.direction === "asc" ? "desc" : state.direction === "desc" ? null : "asc";
      state.sortColumn = state.direction ? index : -1; header.setAttribute("aria-sort", state.direction === "asc" ? "ascending" : state.direction === "desc" ? "descending" : "none");
      indicator.textContent = state.direction === "asc" ? "↑" : state.direction === "desc" ? "↓" : "↕"; state.page = 0; refresh(state);
    };
    const keySort = (event: KeyboardEvent) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); sort(); } };
    header.addEventListener("click", sort); header.addEventListener("keydown", keySort);
    state.disposers.push(() => { header.removeEventListener("click", sort); header.removeEventListener("keydown", keySort); });
  });
  const onSearch = () => { state.query = search.value.trim().toLocaleLowerCase("fr"); state.page = 0; refresh(state); };
  const onPageSize = () => { state.limit = Number(pageSize.value); state.page = 0; refresh(state); };
  const onPrevious = () => { state.page = Math.max(0, state.page - 1); refresh(state); };
  const onNext = () => { state.page += 1; refresh(state); };
  const onDensity = () => { const compact = table.classList.toggle("is-compact"); density.textContent = compact ? "Vue confortable" : "Vue compacte"; density.setAttribute("aria-pressed", String(compact)); };
  search.addEventListener("input", onSearch); pageSize.addEventListener("change", onPageSize); previous.addEventListener("click", onPrevious); next.addEventListener("click", onNext); density.addEventListener("click", onDensity);
  state.disposers.push(() => search.removeEventListener("input", onSearch), () => pageSize.removeEventListener("change", onPageSize), () => previous.removeEventListener("click", onPrevious), () => next.removeEventListener("click", onNext), () => density.removeEventListener("click", onDensity));
  refresh(state); return state;
}

function enhanceStructuredGrid(grid: HTMLElement) {
  if (grid.querySelector(":scope > table") || grid.closest(PRINT_SELECTOR)) return;
  const header = grid.querySelector<HTMLElement>(":scope > .table-head");
  const rows = Array.from(grid.children).filter((element): element is HTMLElement => element instanceof HTMLElement && element.classList.contains("table-row"));
  if (!header || !rows.length) return;
  if (grid.dataset.moventraStructuredGrid !== "ready") { grid.dataset.moventraStructuredGrid = "ready"; grid.classList.add("moventra-structured-grid"); }
  grid.setAttribute("role", "grid");
  grid.setAttribute("aria-rowcount", String(rows.length));
  grid.setAttribute("aria-colcount", String(header.children.length));
  header.setAttribute("role", "row");
  Array.from(header.children).forEach((cell) => cell.setAttribute("role", "columnheader"));
  rows.forEach((row) => {
    row.setAttribute("role", "row"); row.tabIndex = 0; row.setAttribute("aria-selected", "false");
    const select = () => { rows.forEach(candidate => { candidate.classList.toggle("is-selected", candidate === row); candidate.setAttribute("aria-selected", String(candidate === row)); }); };
    if (row.dataset.moventraSelectable !== "ready") {
      row.dataset.moventraSelectable = "ready";
      row.addEventListener("click", event => { if (!(event.target instanceof HTMLElement) || !event.target.closest("button,a,input,select,textarea,label")) select(); });
      row.addEventListener("keydown", event => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); select(); } });
    }
    Array.from(row.children).forEach((cell) => {
      if (!cell.hasAttribute("role") && !/^(BUTTON|LABEL|INPUT|SELECT)$/.test(cell.tagName)) cell.setAttribute("role", "gridcell");
    });
  });
}

export function DataGridEnhancer() {
  useEffect(() => {
    const states = new Map<HTMLTableElement, GridState>(); let scheduled = 0;
    const scan = () => {
      scheduled = 0;
      document.querySelectorAll<HTMLTableElement>("table").forEach((table) => { if (!states.has(table)) { const state = enhance(table); if (state) states.set(table, state); } else refresh(states.get(table)!); });
      document.querySelectorAll<HTMLElement>(".table,.access-user-table,.personnel-table").forEach(enhanceStructuredGrid);
      for (const [table, state] of states) if (!table.isConnected) { state.disposers.forEach(dispose => dispose()); state.toolbar.remove(); states.delete(table); }
    };
    const schedule = () => { if (!scheduled) scheduled = window.setTimeout(scan, 40); };
    scan();
    const observer = new MutationObserver((mutations) => { if (mutations.some((mutation) => Array.from(mutation.addedNodes).some((node) => node instanceof Element && (node.matches("table,tbody,tr") || node.querySelector("table,tbody,tr"))))) schedule(); });
    observer.observe(document.body, { childList: true, subtree: true });
    return () => { observer.disconnect(); if (scheduled) window.clearTimeout(scheduled); states.forEach((state) => { state.disposers.forEach(dispose => dispose()); state.toolbar.remove(); }); };
  }, []);
  return null;
}
