// components/ui/Table.tsx
'use client';

import * as React from 'react';
import { ChevronDownIcon } from '@heroicons/react/20/solid';
import LoadingSpinner from '@/components/ui/LoadingSpinner'; // 👈 Neu

function classNames(...classes: Array<string | boolean | null | undefined>) {
  return classes.filter(Boolean).join(' ');
}

export type SortDirection = 'asc' | 'desc';

export type TableColumn<T> = {
  /** Schlüssel im Datensatz, z.B. 'inventoryNumber' */
  key: keyof T;
  /** Spaltenüberschrift */
  header: string;
  /** Kann die Spalte sortiert werden? */
  sortable?: boolean;
  /** Kann die Spalte ausgeblendet werden? */
  canHide?: boolean;
  /** Optional eigene Klassen für die TH-Zelle */
  headerClassName?: string;
  /** Optional eigene Klassen für die TD-Zelle */
  cellClassName?: string;
  /** Custom Renderer für Zellen (z.B. formatDate) */
  render?: (row: T) => React.ReactNode;
};

export interface TableProps<T> {
  data: T[];
  columns: TableColumn<T>[];
  /** Eindeutige ID pro Zeile */
  getRowId: (row: T) => string;
  /** Checkboxen + Auswahl aktivieren */
  selectable?: boolean;
  /** Callback bei Änderung der Auswahl */
  onSelectionChange?: (selected: T[]) => void;
  /** Optional: Actions in der letzten Spalte rendern */
  renderActions?: (row: T) => React.ReactNode;
  /** Optional: Header-Text für die Actions-Spalte */
  actionsHeader?: string;
  /** Optional: Standard-Sortierspalte */
  defaultSortKey?: keyof T;
  /** Optional: Standard-Sortierrichtung */
  defaultSortDirection?: SortDirection;
  /** Optional: Wenn true, wird statt der Zeilen ein LoadingSpinner angezeigt */
  isLoading?: boolean; // 👈 Neu
}

type SortState<T> = {
  key: keyof T | null;
  direction: SortDirection;
};

export default function Table<T>(props: TableProps<T>) {
  const {
    data,
    columns,
    getRowId,
    selectable = false,
    onSelectionChange,
    renderActions,
    actionsHeader = '',
    defaultSortKey,
    defaultSortDirection = 'asc',
    isLoading = false, // 👈 Neu
  } = props;

  const [sort, setSort] = React.useState<SortState<T>>({
    key: defaultSortKey ?? null,
    direction: defaultSortDirection,
  });

  const [selectedIds, setSelectedIds] = React.useState<string[]>([]);
  const headerCheckboxRef = React.useRef<HTMLInputElement | null>(null);

  // Sortierte Daten
  const sortedData = React.useMemo(() => {
    if (!sort.key) return data;

    const col = columns.find((c) => c.key === sort.key);
    if (!col) return data;

    const sorted = [...data].sort((a, b) => {
      const va = (a as any)[sort.key!];
      const vb = (b as any)[sort.key!];

      if (va == null && vb == null) return 0;
      if (va == null) return sort.direction === 'asc' ? -1 : 1;
      if (vb == null) return sort.direction === 'asc' ? 1 : -1;

      if (typeof va === 'number' && typeof vb === 'number') {
        return sort.direction === 'asc' ? va - vb : vb - va;
      }

      if (typeof va === 'string' && typeof vb === 'string') {
        const na = Number(va);
        const nb = Number(vb);

        if (!Number.isNaN(na) && !Number.isNaN(nb)) {
          return sort.direction === 'asc' ? na - nb : nb - na;
        }
      }

      const sa = va instanceof Date ? va.getTime() : String(va);
      const sb = vb instanceof Date ? vb.getTime() : String(vb);

      if (sa < sb) return sort.direction === 'asc' ? -1 : 1;
      if (sa > sb) return sort.direction === 'asc' ? 1 : -1;
      return 0;
    });

    return sorted;
  }, [data, columns, sort]);

  // Selection / Tri-State Header Checkbox
  React.useLayoutEffect(() => {
    if (!selectable || !headerCheckboxRef.current) return;

    const allIds = sortedData.map((row) => getRowId(row));
    const checkedCount = allIds.filter((id) => selectedIds.includes(id)).length;
    const isAll = checkedCount === allIds.length && allIds.length > 0;
    const isNone = checkedCount === 0;
    const isIndeterminate = !isAll && !isNone;

    headerCheckboxRef.current.checked = isAll;
    headerCheckboxRef.current.indeterminate = isIndeterminate;
  }, [sortedData, selectedIds, selectable, getRowId]);

  React.useEffect(() => {
    if (!onSelectionChange) return;
    const selectedRows = sortedData.filter((row) =>
      selectedIds.includes(getRowId(row)),
    );
    onSelectionChange(selectedRows);
  }, [selectedIds, sortedData, getRowId, onSelectionChange]);

  function toggleSort(key: keyof T) {
    setSort((prev) => {
      if (prev.key === key) {
        return {
          key,
          direction: prev.direction === 'asc' ? 'desc' : 'asc',
        };
      }
      return { key, direction: 'asc' };
    });
  }

  function toggleAll() {
    if (!selectable) return;
    const allIds = sortedData.map((row) => getRowId(row));
    const allSelected =
      allIds.length > 0 && allIds.every((id) => selectedIds.includes(id));

    setSelectedIds(allSelected ? [] : allIds);
  }

  function toggleRow(id: string) {
    if (!selectable) return;
    setSelectedIds((prev) =>
      prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
    );
  }

  const colSpan =
    columns.length + (selectable ? 1 : 0) + (renderActions ? 1 : 0);

  return (
    <div className="relative overflow-visible rounded-lg border border-gray-200 bg-white shadow-sm dark:border-white/10 dark:bg-gray-900/40">
      <div className="overflow-x-auto">
        <table className="min-w-full table-fixed divide-y divide-gray-200 text-left text-sm dark:divide-white/10">
          <thead className="bg-gray-50 dark:bg-gray-800/60">
            <tr>
              {selectable && (
                <th scope="col" className="w-12 px-4">
                  <div className="group grid size-4 grid-cols-1">
                    <input
                      ref={headerCheckboxRef}
                      type="checkbox"
                      onChange={toggleAll}
                      className="col-start-1 row-start-1 appearance-none rounded-sm border border-gray-300 bg-white checked:border-indigo-600 checked:bg-indigo-600 indeterminate:border-indigo-600 indeterminate:bg-indigo-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 dark:border-white/20 dark:bg-gray-800/50 dark:checked:border-indigo-500 dark:checked:bg-indigo-500 dark:indeterminate:border-indigo-500 dark:indeterminate:bg-indigo-500 dark:focus-visible:outline-indigo-500"
                    />
                    <svg
                      className="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white"
                      viewBox="0 0 14 14"
                      fill="none"
                    >
                      <path
                        className="opacity-0 group-has-checked:opacity-100"
                        d="M3 8L6 11L11 3.5"
                        strokeWidth="2"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                      />
                      <path
                        className="opacity-0 group-has-indeterminate:opacity-100"
                        d="M3 7H11"
                        strokeWidth="2"
                        strokeLinecap="round"
                        strokeLinejoin="round"
                      />
                    </svg>
                  </div>
                </th>
              )}

              {columns.map((col) => {
                const isSorted = sort.key === col.key;
                const isSortable = col.sortable;
                const isHideable = col.canHide;

                return (
                  <th
                    key={String(col.key)}
                    scope="col"
                    className={classNames(
                      'py-3.5 px-2 text-left text-sm font-semibold text-gray-900 dark:text-white',
                      col.headerClassName,
                      isHideable ? 'hidden lg:table-cell' : '',
                    )}
                  >
                    {isSortable ? (
                      <button
                        type="button"
                        onClick={() => toggleSort(col.key)}
                        className="group inline-flex items-center"
                      >
                        {col.header}
                        <span
                          className={classNames(
                            'ml-2 flex-none rounded-sm',
                            isSorted
                              ? 'bg-gray-100 text-gray-900 group-hover:bg-gray-200 dark:bg-gray-800 dark:text-white dark:group-hover:bg-gray-700'
                              : 'invisible text-gray-400 group-hover:visible group-focus:visible dark:text-gray-500',
                          )}
                        >
                          <ChevronDownIcon
                            aria-hidden="true"
                            className={classNames(
                              'size-4',
                              isSorted &&
                                sort.direction === 'desc' &&
                                'rotate-180',
                            )}
                          />
                        </span>
                      </button>
                    ) : (
                      col.header
                    )}
                  </th>
                );
              })}

              {renderActions && (
                <th
                  scope="col"
                  className="py-3.5 px-2 text-sm font-semibold text-gray-900 dark:text-white"
                >
                  {actionsHeader}
                </th>
              )}
            </tr>
          </thead>

          <tbody className="divide-y divide-gray-200 bg-white dark:divide-white/10 dark:bg-gray-900/40">
            {isLoading ? (
              // 🔹 Loading-State: Spinner-Zeile statt Daten
              <tr>
                <td
                  colSpan={colSpan}
                  className="px-2 py-8 text-center text-sm text-gray-500 dark:text-gray-400"
                >
                  <div className="flex items-center justify-center gap-3">
                    <LoadingSpinner />
                    <span>Wird geladen …</span>
                  </div>
                </td>
              </tr>
            ) : sortedData.length === 0 ? (
              // 🔹 Empty-State
              <tr>
                <td
                  colSpan={colSpan}
                  className="px-2 py-6 text-center text-sm text-gray-500 dark:text-gray-400"
                >
                  Keine Einträge vorhanden.
                </td>
              </tr>
            ) : (
              // 🔹 Normale Zeilen
              sortedData.map((row) => {
                const id = getRowId(row);
                const isSelected = selectedIds.includes(id);

                return (
                  <tr
                    key={id}
                    className={classNames(
                      isSelected && 'bg-gray-50 dark:bg-gray-800/60',
                    )}
                  >
                    {selectable && (
                      <td className="px-4">
                        <div className="group grid size-4 grid-cols-1">
                          <input
                            type="checkbox"
                            checked={isSelected}
                            onChange={() => toggleRow(id)}
                            className="col-start-1 row-start-1 appearance-none rounded-sm border border-gray-300 bg-white checked:border-indigo-600 checked:bg-indigo-600 indeterminate:border-indigo-600 indeterminate:bg-indigo-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 dark:border-white/20 dark:bg-gray-800/50 dark:checked:border-indigo-500 dark:checked:bg-indigo-500 dark:indeterminate:border-indigo-500 dark:indeterminate:bg-indigo-500 dark:focus-visible:outline-indigo-500"
                          />
                          <svg
                            className="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white"
                            viewBox="0 0 14 14"
                            fill="none"
                          >
                            <path
                              className="opacity-0 group-has-checked:opacity-100"
                              d="M3 8L6 11L11 3.5"
                              strokeWidth="2"
                              strokeLinecap="round"
                              strokeLinejoin="round"
                            />
                            <path
                              className="opacity-0 group-has-indeterminate:opacity-100"
                              d="M3 7H11"
                              strokeWidth="2"
                              strokeLinecap="round"
                              strokeLinejoin="round"
                            />
                          </svg>
                        </div>
                      </td>
                    )}

                    {columns.map((col) => (
                      <td
                        key={String(col.key)}
                        className={classNames(
                          'px-2 py-3 text-sm whitespace-nowrap text-gray-700 dark:text-gray-300',
                          col.cellClassName,
                          col.canHide && 'hidden lg:table-cell',
                        )}
                      >
                        {col.render
                          ? col.render(row)
                          : String((row as any)[col.key] ?? '—')}
                      </td>
                    ))}

                    {renderActions && (
                      <td className="px-2 py-3 text-sm whitespace-nowrap text-right">
                        {renderActions(row)}
                      </td>
                    )}
                  </tr>
                );
              })
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}
