import { CSSProperties, ReactNode, useState } from "react";
import {
  Table,
  Button,
  Menu,
  Checkbox,
  Group,
  Text,
  Pagination,
  Loader,
  Center,
  Paper,
  Select,
} from "@mantine/core";
import { IconRefresh, IconAdjustmentsHorizontal , 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;
  /** Label for the View menu; falls back to `header` when it is a plain string. */
  label?: string;
}

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;
  /** Shows a page-size <Select> when given; called with the chosen size. */
  onPageSizeChange?: (pageSize: number) => void;
  /** Options for the page-size select. Default [10, 20, 30, 40, 50]. */
  pageSizeOptions?: number[];
  refresh?: () => void;
  /** Server-side search — debounced internally. Omit to hide the search box. */
  onSearchChange?: (q: string) => void;
  isLoading?: boolean;
  emptyText?: string;
  verticalSpacing?: string | number;
  rowStyle?: (row: T, index: number) => CSSProperties | undefined;
  /** Makes rows clickable (adds pointer cursor). */
  onRowClick?: (row: T) => void;
  /** Card title, top-left. Defaults to `tableName`, which every caller already passes. */
  title?: ReactNode;
  /** Search box, filters, export — rendered top-right before Refresh/View. */
  toolbar?: ReactNode;
}

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,
  onPageSizeChange,
  pageSizeOptions = [10, 20, 30, 40, 50],
  refresh,
  isLoading = false,
  emptyText,
  verticalSpacing = "sm",
  rowStyle,
  onRowClick,
  title,
  toolbar,
}: 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);

  const heading = title ?? tableName;
  const from = itemCount === 0 ? 0 : pageIndex * pageSize + 1;
  const to = Math.min(itemCount, pageIndex * pageSize + data.length);

  return (
    <Paper withBorder radius="lg" p={0}>
      <Group justify="space-between" px="md" py="sm" wrap="wrap" gap="sm">
        <Group gap="xs">
          {heading && (
            <Text fw={600} size="sm">
              {heading}
            </Text>
          )}
        </Group>
        <Group gap="xs" wrap="wrap">
          {toolbar}
          {refresh && (
            <Button
              variant="default"
              size="sm"
              leftSection={<IconRefresh size={16} />}
              onClick={refresh}
              loading={isLoading}
            >
              {t("common.refresh", "Refresh")}
            </Button>
          )}
          <Menu
            closeOnItemClick={false}
            shadow="md"
            position="bottom-end"
            width={220}
          >
            <Menu.Target>
              <Button
                variant="default"
                size="sm"
                leftSection={<IconAdjustmentsHorizontal  size={16} />}
              >
                {t("common.view", "View")}
              </Button>
            </Menu.Target>
            <Menu.Dropdown>
              <Menu.Label>
                {t("common.toggleColumns", "Toggle columns")}
              </Menu.Label>
              {columns.map((col, i) => {
                // A ReactNode header (e.g. a live checkbox or a clickable sort
                // control) can't be reused as a menu-item label — skip it
                // rather than nesting interactive markup inside the label.
                const label = col.label ?? (typeof col.header === "string" ? col.header : null);
                if (label === null) return null;
                return (
                  <Menu.Item key={i} onClick={() => toggleColumn(i)}>
                    <Checkbox
                      label={label}
                      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 verticalSpacing={verticalSpacing}>
          <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}
                  onClick={onRowClick ? () => onRowClick(row) : undefined}
                  style={{
                    ...(onRowClick ? { cursor: "pointer" } : undefined),
                    ...rowStyle?.(row, 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>

      <Group
        justify="space-between"
        px="md"
        py="sm"
        style={{ borderTop: "1px solid var(--ema-border-subtle)" }}
      >
        <Text size="xs" c="dimmed">
          {t("common.showingRange", {
            from,
            to,
            total: itemCount,
            defaultValue: "Showing {{from}}–{{to}} of {{total}}",
          })}
        </Text>
        <Group gap="sm">
          {onPageSizeChange && (
            <Select
              size="sm"
              w={100}
              data={pageSizeOptions.map((n) => String(n))}
              value={String(pageSize)}
              onChange={(v) => v && onPageSizeChange(Number(v))}
              allowDeselect={false}
            />
          )}
          {itemCount > pageSize && (
            <Pagination
              total={Math.ceil(itemCount / pageSize)}
              value={pageIndex + 1}
              onChange={(page) => onPageChange(page - 1)}
              size="sm"
              siblings={0}
              boundaries={1}
            />
          )}
        </Group>
      </Group>
    </Paper>
  );
}
