'use client';

import { useCallback, useMemo, useState } from 'react';
import {
  loadTablePrefs,
  mergeColumnOrder,
  resetTablePrefs,
  resolveVisibleColumns,
  saveTablePrefs,
  type AdminTablePrefs,
  type TableDensity,
} from '@/lib/admin/table-prefs';
import type { ColumnDef } from './AdminTable';

const DEFAULT_PREFS: AdminTablePrefs = {
  hiddenKeys: [],
  columnOrder: [],
  density: 'comfortable',
};

function readPrefs(tableId: string): AdminTablePrefs {
  if (typeof window === 'undefined') return DEFAULT_PREFS;
  return loadTablePrefs(tableId) ?? DEFAULT_PREFS;
}

export function useAdminTableLayout<T>(tableId: string, columns: ColumnDef<T>[]) {
  const [prefs, setPrefs] = useState<AdminTablePrefs>(() => readPrefs(tableId));

  const columnKeys = useMemo(() => columns.map((c) => c.key), [columns]);

  const orderedColumns = useMemo(() => {
    const order = mergeColumnOrder(
      prefs.columnOrder.length > 0 ? prefs.columnOrder : columnKeys,
      columnKeys,
    );
    return order
      .map((key) => columns.find((c) => c.key === key))
      .filter((c): c is ColumnDef<T> => Boolean(c));
  }, [columns, columnKeys, prefs.columnOrder]);

  const visibleColumns = useMemo(
    () => resolveVisibleColumns(orderedColumns, prefs.hiddenKeys),
    [orderedColumns, prefs.hiddenKeys],
  );

  const persist = useCallback(
    (partial: Partial<AdminTablePrefs>) => {
      setPrefs((prev) => {
        const next = { ...prev, ...partial };
        saveTablePrefs(tableId, partial);
        return next;
      });
    },
    [tableId],
  );

  const toggleColumnHidden = useCallback(
    (key: string) => {
      const col = orderedColumns.find((c) => c.key === key);
      if (!col || col.hideable === false) return;

      const hidden = new Set(prefs.hiddenKeys);
      const currentlyVisible = resolveVisibleColumns(orderedColumns, prefs.hiddenKeys);
      if (hidden.has(key)) {
        hidden.delete(key);
      } else if (currentlyVisible.length <= 1) {
        return;
      } else {
        hidden.add(key);
      }
      persist({ hiddenKeys: Array.from(hidden) });
    },
    [orderedColumns, persist, prefs.hiddenKeys],
  );

  const resetColumns = useCallback(() => {
    resetTablePrefs(tableId);
    setPrefs(DEFAULT_PREFS);
  }, [tableId]);

  const setDensity = useCallback((density: TableDensity) => persist({ density }), [persist]);

  const moveColumn = useCallback(
    (key: string, direction: 'left' | 'right') => {
      const order = mergeColumnOrder(
        prefs.columnOrder.length > 0 ? prefs.columnOrder : columnKeys,
        columnKeys,
      );
      const idx = order.indexOf(key);
      if (idx < 0) return;
      const swapIdx = direction === 'left' ? idx - 1 : idx + 1;
      if (swapIdx < 0 || swapIdx >= order.length) return;
      const next = [...order];
      [next[idx], next[swapIdx]] = [next[swapIdx]!, next[idx]!];
      persist({ columnOrder: next });
    },
    [columnKeys, persist, prefs.columnOrder],
  );

  const reorderColumns = useCallback(
    (fromKey: string, toKey: string) => {
      const order = mergeColumnOrder(
        prefs.columnOrder.length > 0 ? prefs.columnOrder : columnKeys,
        columnKeys,
      );
      const fromIdx = order.indexOf(fromKey);
      const toIdx = order.indexOf(toKey);
      if (fromIdx < 0 || toIdx < 0 || fromIdx === toIdx) return;
      const next = [...order];
      next.splice(fromIdx, 1);
      next.splice(toIdx, 0, fromKey);
      persist({ columnOrder: next });
    },
    [columnKeys, persist, prefs.columnOrder],
  );

  return {
    visibleColumns,
    orderedColumns,
    density: prefs.density,
    hiddenKeys: prefs.hiddenKeys,
    toggleColumnHidden,
    resetColumns,
    setDensity,
    moveColumn,
    reorderColumns,
  };
}

export type AdminTableLayoutApi<T> = ReturnType<typeof useAdminTableLayout<T>>;
