import { ReactNode, useState } from "react";
import {
  Table,
  Button,
  Menu,
  Checkbox,
  Group,
  Text,
  Pagination,
  Loader,
  Center,
  Paper,
  Badge,
} from "@mantine/core";
import { IconRefresh, IconEye, IconInbox } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";

export interface AdvancedColumn<T> {
  header: ReactNode;
  /** Dot-path into the row, used when no `cell` is given (e.g. "expectation.name"). */
  accessorKey?: string;
  cell?: (ctx: { row: { original: T }; value: unknown }) => ReactNode;
  size?: number;
  align?: "left" | "center" | "right";
  /** Whether column starts visible. Default true. */
  enabled?: boolean;
}

interface AdvancedTableProps<T> {
  columns: AdvancedColumn<T>[];
  data: T[];
  tableName: string;
  /** Total item count on the server (drives pagination), not data.length. */
  itemCount: number;
  /** 0-based current page. */
  pageIndex: number;
  onPageChange: (pageIndex: number) => void;
  pageSize?: number;
  refresh?: () => void;
  /** Server-side search — debounced internally. Omit to hide the search box. */
  onSearchChange?: (q: string) => void;
  isLoading?: boolean;
  emptyText?: string;
}

function getByPath(obj: unknown, path?: string): unknown {
  if (!path) return undefined;
  return path
    .split(".")
    .reduce<unknown>(
      (acc, key) =>
        acc && typeof acc === "object"
          ? (acc as Record<string, unknown>)[key]
          : undefined,
      obj,
    );
}

export function AdvancedTable<T extends { id?: string | number }>({
  columns,
  data,
  tableName,
  itemCount,
  pageIndex,
  onPageChange,
  pageSize = 10,
  refresh,
  isLoading = false,
  emptyText,
}: AdvancedTableProps<T>) {
  const { t } = useTranslation();
  const [visible, setVisible] = useState<boolean[]>(
    columns.map((c) => c.enabled ?? true),
  );
  const toggleColumn = (i: number) =>
    setVisible((prev) => {
      if (prev[i] && prev.filter(Boolean).length === 1) return prev; // keep at least one column visible
      return prev.map((v, idx) => (idx === i ? !v : v));
    });
  const shownColumns = columns.filter((_, i) => visible[i] ?? true);

  return (
    <Paper radius="md" p="md">
      <Group justify="space-between" mb="md">
        <Group gap="xs">
          <Text fw={600}>{""}</Text>
        </Group>
        <Group gap="xs">
          <Menu
            closeOnItemClick={false}
            shadow="md"
            position="bottom-end"
            width={220}
          >
            {refresh && (
              <Button
                variant="default"
                size="sm"
                leftSection={<IconRefresh size={16} />}
                onClick={refresh}
                loading={isLoading}
              >
                {t("common.refresh", "Refresh")}
              </Button>
            )}
            <Menu.Target>
              <Button
                variant="default"
                size="sm"
                leftSection={<IconEye size={16} />}
              >
                {t("common.view", "View")}
              </Button>
            </Menu.Target>
            <Menu.Dropdown>
              <Menu.Label>
                {t("common.toggleColumns", "Toggle columns")}
              </Menu.Label>
              {columns.map((col, i) => (
                <Menu.Item key={i} onClick={() => toggleColumn(i)}>
                  <Checkbox
                    label={col.header}
                    checked={visible[i] ?? true}
                    disabled={
                      visible.filter(Boolean).length === 1 &&
                      (visible[i] ?? true)
                    }
                    readOnly
                    tabIndex={-1}
                    styles={{
                      input: { cursor: "pointer" },
                      label: { cursor: "pointer" },
                    }}
                  />
                </Menu.Item>
              ))}
            </Menu.Dropdown>
          </Menu>
        </Group>
      </Group>

      <Table.ScrollContainer minWidth={480}>
        <Table
          striped
          highlightOnHover
          withTableBorder
          withColumnBorders
          verticalSpacing="sm"
        >
          <Table.Thead>
            <Table.Tr>
              {shownColumns.map((col, i) => (
                <Table.Th
                  key={i}
                  style={{ width: col.size, textAlign: col.align }}
                >
                  {col.header}
                </Table.Th>
              ))}
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {isLoading ? (
              <Table.Tr>
                <Table.Td colSpan={shownColumns.length}>
                  <Center py="xl">
                    <Loader size="sm" />
                  </Center>
                </Table.Td>
              </Table.Tr>
            ) : data.length === 0 ? (
              <Table.Tr>
                <Table.Td colSpan={shownColumns.length}>
                  <Center py="xl">
                    <Group gap="xs" c="dimmed">
                      <IconInbox size={18} />
                      <Text c="dimmed">
                        {emptyText ?? t("common.noResult", "No results")}
                      </Text>
                    </Group>
                  </Center>
                </Table.Td>
              </Table.Tr>
            ) : (
              data.map((row, rowIndex) => (
                <Table.Tr key={row.id ?? rowIndex}>
                  {shownColumns.map((col, i) => {
                    const value = getByPath(row, col.accessorKey);
                    return (
                      <Table.Td key={i} style={{ textAlign: col.align }}>
                        {col.cell
                          ? col.cell({ row: { original: row }, value })
                          : ((value as ReactNode) ?? "-")}
                      </Table.Td>
                    );
                  })}
                </Table.Tr>
              ))
            )}
          </Table.Tbody>
        </Table>
      </Table.ScrollContainer>

      {itemCount > pageSize && (
        <Group justify="flex-end" mt="md">
          <Pagination
            total={Math.ceil(itemCount / pageSize)}
            value={pageIndex + 1}
            onChange={(page) => onPageChange(page - 1)}
            size="sm"
          />
        </Group>
      )}
    </Paper>
  );
}
