"use client";

import { cn } from "@/shared/lib/utils";
import { useT } from "@/shared/i18n/client";
import { Button } from "@/presentation/components/ui/button";
import { Input } from "@/presentation/components/ui/input";
import { Checkbox } from "@/presentation/components/ui/checkbox";
import { Skeleton } from "@/presentation/components/ui/skeleton";
import {
  ChevronUp,
  ChevronDown,
  ChevronsUpDown,
  Search,
  ChevronLeft,
  ChevronRight,
} from "lucide-react";

export interface Column<T> {
  key: string;
  label: string;
  sortable?: boolean;
  render?: (row: T) => React.ReactNode;
  className?: string;
  truncate?: boolean | number;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
interface ServerDataTableProps<T extends Record<string, any>> {
  columns: Column<T>[];
  data: T[];
  total: number;
  page: number;
  totalPages: number;
  loading?: boolean;
  search?: string;
  onSearchChange?: (search: string) => void;
  onPageChange: (page: number) => void;
  onSortChange?: (orderBy: string, order: "ASC" | "DESC") => void;
  sortBy?: string;
  sortOrder?: "ASC" | "DESC";
  searchPlaceholder?: string;
  onRowClick?: (row: T) => void;
  emptyMessage?: string;
  toolbar?: React.ReactNode;
  /** Optional row selection (leading checkbox column). Fully opt-in. */
  selectable?: boolean;
  /** How to identify a row for selection. Defaults to `row.id`. */
  getRowId?: (row: T) => string | number;
  /** Currently-selected ids (may span pages). */
  selectedIds?: Array<string | number>;
  /** Toggle a single row's selection. */
  onToggleRow?: (row: T) => void;
  /** Select/clear every row on the current page. */
  onToggleAllOnPage?: (checked: boolean) => void;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export default function ServerDataTable<T extends Record<string, any>>({
  columns,
  data,
  total,
  page,
  totalPages,
  loading,
  search,
  onSearchChange,
  onPageChange,
  onSortChange,
  sortBy,
  sortOrder,
  searchPlaceholder,
  onRowClick,
  emptyMessage,
  toolbar,
  selectable = false,
  getRowId,
  selectedIds,
  onToggleRow,
  onToggleAllOnPage,
}: ServerDataTableProps<T>) {
  const t = useT();
  const placeholder = searchPlaceholder ?? t.common.search;
  const empty = emptyMessage ?? t.common.noData;
  const colCount = columns.length + (selectable ? 1 : 0);
  const rowId = (row: T): string | number =>
    getRowId ? getRowId(row) : (row.id as string | number);
  const selectedSet = new Set(selectedIds ?? []);
  const allOnPageSelected =
    selectable && data.length > 0 && data.every((row) => selectedSet.has(rowId(row)));
  const someOnPageSelected =
    selectable && !allOnPageSelected && data.some((row) => selectedSet.has(rowId(row)));
  const handleSort = (key: string) => {
    if (!onSortChange) return;
    if (sortBy === key) {
      onSortChange(key, sortOrder === "ASC" ? "DESC" : "ASC");
    } else {
      onSortChange(key, "ASC");
    }
  };

  const SortIcon = ({ colKey }: { colKey: string }) => {
    if (sortBy !== colKey)
      return <ChevronsUpDown className="w-3.5 h-3.5 text-muted-foreground/50" />;
    return sortOrder === "ASC" ? (
      <ChevronUp className="w-3.5 h-3.5 text-primary" />
    ) : (
      <ChevronDown className="w-3.5 h-3.5 text-primary" />
    );
  };

  return (
    <div className="space-y-3">
      <div className="flex flex-col sm:flex-row items-start sm:items-center gap-3">
        {onSearchChange && (
          <div className="flex items-center gap-2 bg-muted/50 rounded-lg px-3 py-2 w-full sm:max-w-xs">
            <Search className="w-4 h-4 text-muted-foreground flex-shrink-0" />
            <Input
              value={search ?? ""}
              onChange={(e) => onSearchChange(e.target.value)}
              placeholder={placeholder}
              className="border-0 bg-transparent p-0 h-auto text-sm focus-visible:ring-0 shadow-none"
            />
          </div>
        )}
        {toolbar && <div className="flex items-end gap-2 flex-wrap">{toolbar}</div>}
      </div>

      <div className="rounded-xl border border-border overflow-hidden bg-card shadow-sm">
        <div className="overflow-x-auto">
          <table className="w-full text-sm">
            <thead>
              <tr className="border-b border-border bg-muted/30">
                {selectable && (
                  <th className="px-4 py-3 w-10">
                    <Checkbox
                      aria-label={t.common.all}
                      checked={
                        allOnPageSelected
                          ? true
                          : someOnPageSelected
                          ? "indeterminate"
                          : false
                      }
                      onCheckedChange={() =>
                        onToggleAllOnPage?.(!allOnPageSelected)
                      }
                    />
                  </th>
                )}
                {columns.map((col) => (
                  <th
                    key={col.key}
                    className={cn(
                      "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-muted-foreground whitespace-nowrap",
                      col.sortable &&
                        "cursor-pointer hover:text-foreground select-none",
                      col.className
                    )}
                    onClick={() => col.sortable && handleSort(col.key)}
                  >
                    <div className="flex items-center gap-1.5">
                      {col.label}
                      {col.sortable && <SortIcon colKey={col.key} />}
                    </div>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody className="divide-y divide-border">
              {/* Skeletons only when there's nothing to show yet. During background refetches we keep the
                  current rows on screen (stale-while-revalidate) so the table doesn't blank out. */}
              {loading && data.length === 0 ? (
                Array.from({ length: 5 }).map((_, idx) => (
                  <tr key={idx}>
                    {selectable && (
                      <td className="px-4 py-3.5">
                        <Skeleton className="h-4 w-4" />
                      </td>
                    )}
                    {columns.map((col) => (
                      <td key={col.key} className="px-4 py-3.5">
                        <Skeleton className="h-4 w-full" />
                      </td>
                    ))}
                  </tr>
                ))
              ) : data.length === 0 ? (
                <tr>
                  <td
                    colSpan={colCount}
                    className="px-4 py-12 text-center text-muted-foreground text-sm"
                  >
                    {empty}
                  </td>
                </tr>
              ) : (
                data.map((row, idx) => {
                  const id = rowId(row);
                  return (
                  <tr
                    key={id ?? idx}
                    className={cn(
                      "transition-colors duration-100",
                      selectable && selectedSet.has(id) && "bg-primary/5",
                      onRowClick
                        ? "cursor-pointer hover:bg-muted/40"
                        : "hover:bg-muted/20"
                    )}
                    onClick={() => onRowClick?.(row)}
                  >
                    {selectable && (
                      <td
                        className="px-4 py-3.5 w-10"
                        onClick={(e) => e.stopPropagation()}
                      >
                        <Checkbox
                          aria-label={t.common.search}
                          checked={selectedSet.has(id)}
                          onCheckedChange={() => onToggleRow?.(row)}
                        />
                      </td>
                    )}
                    {columns.map((col) => {
                      const maxWidth =
                        typeof col.truncate === "number"
                          ? `${col.truncate}px`
                          : col.truncate
                          ? "320px"
                          : undefined;
                      return (
                        <td
                          key={col.key}
                          style={maxWidth ? { maxWidth } : undefined}
                          className={cn(
                            "px-4 py-3.5 text-foreground",
                            col.truncate && "align-top",
                            col.className
                          )}
                        >
                          {col.truncate ? (
                            <div className="min-w-0 [&_*]:truncate [&>*]:min-w-0">
                              {col.render
                                ? col.render(row)
                                : String(
                                    (row as Record<string, unknown>)[col.key] ??
                                      "\u2014"
                                  )}
                            </div>
                          ) : col.render ? (
                            col.render(row)
                          ) : (
                            String(
                              (row as Record<string, unknown>)[col.key] ?? "\u2014"
                            )
                          )}
                        </td>
                      );
                    })}
                  </tr>
                  );
                })
              )}
            </tbody>
          </table>
        </div>

        <div className="flex items-center justify-between px-4 py-3 border-t border-border bg-muted/20">
          <span className="text-xs text-muted-foreground">
            {t.common.resultsCount(total)}
          </span>
          {totalPages > 1 && (
            <div className="flex items-center gap-1.5">
              <Button
                variant="outline"
                size="sm"
                onClick={() => onPageChange(Math.max(1, page - 1))}
                disabled={page === 1}
                className="h-7 w-7 p-0"
              >
                <ChevronLeft className="w-3.5 h-3.5" />
              </Button>
              <span className="text-xs text-muted-foreground px-2 font-medium">
                {page} / {totalPages}
              </span>
              <Button
                variant="outline"
                size="sm"
                onClick={() => onPageChange(Math.min(totalPages, page + 1))}
                disabled={page === totalPages}
                className="h-7 w-7 p-0"
              >
                <ChevronRight className="w-3.5 h-3.5" />
              </Button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
