import {
  Badge,
  Box,
  Button,
  Checkbox,
  Code,
  Divider,
  Drawer,
  Group,
  Paper,
  Popover,
  ScrollArea,
  Select,
  Stack,
  Table,
  Text,
  Tooltip,
} from "@mantine/core";
import { DatePickerInput, type DatesRangeValue } from "@mantine/dates";
import { useDisclosure } from "@mantine/hooks";
import {
  IconCalendar,
  IconFilter,
  IconSearch,
  IconX,
} from "@tabler/icons-react";
import {
  flexRender,
  MRT_GlobalFilterTextInput,
  MRT_TableBodyCellValue,
  MRT_TablePagination,
  useMantineReactTable,
  type MRT_ColumnDef,
} from "mantine-react-table";
import { useMemo, useState } from "react";

interface HistoryLog {
  id: string;
  entity_type: "agent" | "prompt";
  entity_id: string;
  action: "create" | "update" | "delete";
  performed_by: string;
  performed_at: string;
  before_data: any;
  after_data: any;
}

const ACTION_COLORS: Record<string, string> = {
  create: "green",
  update: "blue",
  delete: "red",
};

const SKIP_KEYS = new Set([
  "id",
  "created_at",
  "updated_at",
  "created_by",
  "updated_by",
]);

function getChangedFields(
  before: any,
  after: any,
): { key: string; from: any; to: any }[] {
  if (!before || !after) return [];
  const allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);
  const changes: { key: string; from: any; to: any }[] = [];
  for (const key of allKeys) {
    if (SKIP_KEYS.has(key)) continue;
    const fromVal = before[key];
    const toVal = after[key];
    if (JSON.stringify(fromVal) !== JSON.stringify(toVal)) {
      changes.push({ key, from: fromVal, to: toVal });
    }
  }
  return changes;
}

function formatFieldName(key: string): string {
  return key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}

function formatValue(val: any): string {
  if (val === null || val === undefined) return "—";
  if (typeof val === "object") return JSON.stringify(val, null, 2);
  return String(val);
}

function truncateValue(val: string, max = 120): string {
  return val.length > max ? val.slice(0, max) + "…" : val;
}

// ── Detail Drawer ───────────────────────────────────────────────────────────
const DetailDrawer: React.FC<{
  log: HistoryLog | null;
  opened: boolean;
  onClose: () => void;
}> = ({ log, opened, onClose }) => {
  if (!log) return null;

  const entityName =
    log.after_data?.agent_name ??
    log.after_data?.prompt_name ??
    log.before_data?.agent_name ??
    log.before_data?.prompt_name ??
    log.entity_id;

  const changes =
    log.action === "update"
      ? getChangedFields(log.before_data, log.after_data)
      : [];
  const displayData =
    log.action === "delete" ? log.before_data : log.after_data;

  return (
    <Drawer
      opened={opened}
      onClose={onClose}
      title={
        <Group gap="sm">
          <Badge
            size="lg"
            variant="light"
            color={ACTION_COLORS[log.action] ?? "gray"}
          >
            {log.action}
          </Badge>
          <Badge size="lg" variant="outline" color="gray">
            {log.entity_type}
          </Badge>
          <Text fw={600} size="sm">
            {entityName}
          </Text>
        </Group>
      }
      position="right"
      size="lg"
      padding="md"
    >
      <Stack gap="md">
        {/* Meta info */}
        <Paper p="sm" withBorder radius="sm" bg="gray.0">
          <Group gap="xl">
            <Box>
              <Text size="xs" c="dimmed">
                Performed By
              </Text>
              <Text size="sm" fw={500}>
                {log.performed_by}
              </Text>
            </Box>
            <Box>
              <Text size="xs" c="dimmed">
                Date
              </Text>
              <Text size="sm" fw={500}>
                {new Date(log.performed_at).toLocaleString()}
              </Text>
            </Box>
            <Box>
              <Text size="xs" c="dimmed">
                Entity ID
              </Text>
              <Code fz={11}>{log.entity_id}</Code>
            </Box>
          </Group>
        </Paper>

        {/* Update: show diff */}
        {log.action === "update" && changes.length > 0 && (
          <>
            <Divider label="Changes" labelPosition="left" />
            <Stack gap="xs">
              {changes.map((ch) => (
                <Paper key={ch.key} p="sm" withBorder radius="sm">
                  <Text size="xs" fw={600} mb={4}>
                    {formatFieldName(ch.key)}
                  </Text>
                  <Group gap="xs" align="flex-start" wrap="nowrap">
                    <Box style={{ flex: 1 }}>
                      <Text size="xs" c="dimmed" mb={2}>
                        Before
                      </Text>
                      <ScrollArea.Autosize mah={160}>
                        <Code
                          block
                          fz={11}
                          c="red.7"
                          bg="red.0"
                          style={{
                            whiteSpace: "pre-wrap",
                            wordBreak: "break-word",
                          }}
                        >
                          {formatValue(ch.from)}
                        </Code>
                      </ScrollArea.Autosize>
                    </Box>
                    <Text c="dimmed" mt={18}>
                      →
                    </Text>
                    <Box style={{ flex: 1 }}>
                      <Text size="xs" c="dimmed" mb={2}>
                        After
                      </Text>
                      <ScrollArea.Autosize mah={160}>
                        <Code
                          block
                          fz={11}
                          c="green.7"
                          bg="green.0"
                          style={{
                            whiteSpace: "pre-wrap",
                            wordBreak: "break-word",
                          }}
                        >
                          {formatValue(ch.to)}
                        </Code>
                      </ScrollArea.Autosize>
                    </Box>
                  </Group>
                </Paper>
              ))}
            </Stack>
          </>
        )}

        {log.action === "update" && changes.length === 0 && (
          <Text size="sm" c="dimmed" ta="center" py="md">
            No field changes detected.
          </Text>
        )}

        {/* Create / Delete: show full data */}
        {(log.action === "create" || log.action === "delete") &&
          displayData && (
            <>
              <Divider
                label={
                  log.action === "create" ? "Created Data" : "Deleted Data"
                }
                labelPosition="left"
              />
              <Stack gap="xs">
                {Object.entries(displayData)
                  .filter(([key]) => !SKIP_KEYS.has(key))
                  .map(([key, val]) => (
                    <Group key={key} gap="sm" align="flex-start" wrap="nowrap">
                      <Text
                        size="xs"
                        fw={600}
                        w={140}
                        style={{ flexShrink: 0 }}
                      >
                        {formatFieldName(key)}
                      </Text>
                      <ScrollArea.Autosize mah={120} style={{ flex: 1 }}>
                        <Code
                          fz={11}
                          block
                          style={{
                            whiteSpace: "pre-wrap",
                            wordBreak: "break-word",
                          }}
                        >
                          {formatValue(val)}
                        </Code>
                      </ScrollArea.Autosize>
                    </Group>
                  ))}
              </Stack>
            </>
          )}

        {!displayData && (
          <Text size="sm" c="dimmed" ta="center" py="md">
            No data recorded for this action.
          </Text>
        )}
      </Stack>
    </Drawer>
  );
};

// ── Changes Summary (inline in table) ───────────────────────────────────────
const ChangesSummary: React.FC<{ log: HistoryLog }> = ({ log }) => {
  if (log.action === "create") {
    return (
      <Text size="xs" c="green.7">
        New {log.entity_type} created
      </Text>
    );
  }
  if (log.action === "delete") {
    return (
      <Text size="xs" c="red.7">
        {log.entity_type} deleted
      </Text>
    );
  }
  // update — show changed field names
  const changes = getChangedFields(log.before_data, log.after_data);
  if (changes.length === 0)
    return (
      <Text size="xs" c="dimmed">
        No changes
      </Text>
    );
  const names = changes.map((c) => formatFieldName(c.key));
  const display =
    names.length <= 3
      ? names.join(", ")
      : `${names.slice(0, 3).join(", ")} +${names.length - 3} more`;
  return (
    <Tooltip label={names.join(", ")} disabled={names.length <= 3}>
      <Text size="xs" c="blue.7">
        {display}
      </Text>
    </Tooltip>
  );
};

// ── Main Page ───────────────────────────────────────────────────────────────
const HistoryClientPage: React.FC<{ logs: HistoryLog[] }> = ({ logs }) => {
  const [filterEntity, setFilterEntity] = useState<string | null>(null);
  const [filterAction, setFilterAction] = useState<string | null>(null);
  const [filterPerformedBy, setFilterPerformedBy] = useState<string[]>([]);
  const [filterDateRange, setFilterDateRange] = useState<DatesRangeValue>([
    null,
    null,
  ]);
  const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25 });
  const [selectedLog, setSelectedLog] = useState<HistoryLog | null>(null);
  const [drawerOpened, { open: openDrawer, close: closeDrawer }] =
    useDisclosure(false);

  // Derive unique "performed by" options from data
  const performedByOptions = useMemo(
    () =>
      [...new Set(logs.map((l) => l.performed_by).filter(Boolean))]
        .sort()
        .map((v) => ({ value: v, label: v })),
    [logs],
  );

  const filteredData = useMemo(() => {
    let result = [...logs];
    if (filterEntity)
      result = result.filter((r) => r.entity_type === filterEntity);
    if (filterAction) result = result.filter((r) => r.action === filterAction);
    if (filterPerformedBy.length > 0)
      result = result.filter((r) => filterPerformedBy.includes(r.performed_by));
    if (filterDateRange[0] || filterDateRange[1]) {
      const from = filterDateRange[0]
        ? new Date(filterDateRange[0]).setHours(0, 0, 0, 0)
        : null;
      const to = filterDateRange[1]
        ? new Date(filterDateRange[1]).setHours(23, 59, 59, 999)
        : null;
      result = result.filter((r) => {
        const d = new Date(r.performed_at).getTime();
        if (from && d < from) return false;
        if (to && d > to) return false;
        return true;
      });
    }
    return result;
  }, [logs, filterEntity, filterAction, filterPerformedBy, filterDateRange]);

  const hasActiveFilters = !!(
    filterEntity ||
    filterAction ||
    filterPerformedBy.length > 0 ||
    filterDateRange[0] ||
    filterDateRange[1]
  );

  const onRowClick = (log: HistoryLog) => {
    setSelectedLog(log);
    openDrawer();
  };

  const columns: MRT_ColumnDef<HistoryLog>[] = [
    {
      accessorKey: "performed_at",
      header: "Date",
      minSize: 160,
      enableGlobalFilter: false,
      Cell: ({ row }) => {
        const d = new Date(row.original.performed_at);
        return (
          <Text size="xs">
            {d.toLocaleDateString()}{" "}
            {d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
          </Text>
        );
      },
    },
    {
      accessorKey: "action",
      header: "Action",
      minSize: 90,
      enableGlobalFilter: false,
      Cell: ({ row }) => (
        <Badge
          size="sm"
          variant="light"
          color={ACTION_COLORS[row.original.action] ?? "gray"}
        >
          {row.original.action}
        </Badge>
      ),
    },
    {
      accessorKey: "entity_type",
      header: "Entity",
      minSize: 90,
      enableGlobalFilter: false,
      Cell: ({ row }) => (
        <Badge size="sm" variant="outline" color="gray">
          {row.original.entity_type}
        </Badge>
      ),
    },
    {
      id: "entity_name",
      header: "Name",
      minSize: 180,
      accessorFn: (row) => {
        const data = row.after_data ?? row.before_data;
        return data?.agent_name ?? data?.prompt_name ?? row.entity_id;
      },
      Cell: ({ row }) => {
        const data = row.original.after_data ?? row.original.before_data;
        const name =
          data?.agent_name ?? data?.prompt_name ?? row.original.entity_id;
        return (
          <Text size="xs" fw={500}>
            {name}
          </Text>
        );
      },
    },
    {
      id: "changes",
      header: "Changes",
      minSize: 200,
      enableSorting: false,
      accessorFn: (row) => {
        const changes = getChangedFields(row.before_data, row.after_data);
        return changes.map((c) => formatFieldName(c.key)).join(", ");
      },
      Cell: ({ row }) => <ChangesSummary log={row.original} />,
    },
    {
      accessorKey: "performed_by",
      header: "Performed By",
      minSize: 160,
    },
  ];

  const table = useMantineReactTable({
    columns,
    data: filteredData,
    enableSorting: true,
    enableRowSelection: false,
    getRowId: (row) => row.id,
    state: { pagination },
    onPaginationChange: (updater) => {
      const next =
        typeof updater === "function" ? updater(pagination) : updater;
      setPagination(next);
      window.scrollTo({ top: 0, behavior: "smooth" });
    },
    initialState: { showGlobalFilter: true },
    paginationDisplayMode: "pages",
    mantinePaginationProps: { rowsPerPageOptions: ["25", "50", "100"], p: 0 },
    mantineSearchTextInputProps: { size: "sm" },
    enablePinning: false,
  });

  return (
    <Stack>
      <DetailDrawer
        log={selectedLog}
        opened={drawerOpened}
        onClose={closeDrawer}
      />

      <Group gap="sm" align="center" wrap="wrap">
        <Group gap={4} align="center">
          <IconFilter size={16} color="var(--mantine-color-gray-6)" />
          <Text size="sm" c="dimmed" fw={500}>
            Filters:
          </Text>
        </Group>
        <Select
          size="sm"
          placeholder="All entities"
          clearable
          data={[
            { value: "agent", label: "Agent" },
            { value: "prompt", label: "Prompt" },
          ]}
          value={filterEntity}
          onChange={setFilterEntity}
          style={{ width: 160 }}
        />
        <Select
          size="sm"
          placeholder="All actions"
          clearable
          data={[
            { value: "create", label: "Created" },
            { value: "update", label: "Updated" },
            { value: "delete", label: "Deleted" },
          ]}
          value={filterAction}
          onChange={setFilterAction}
          style={{ width: 160 }}
        />
        <Popover width={320} position="bottom-start" shadow="md">
          <Popover.Target>
            <Button
              size="sm"
              variant="default"
              color="gray"
              style={{ fontWeight: 400, width: 180 }}
            >
              {filterPerformedBy.length > 0
                ? `${filterPerformedBy.length} user${filterPerformedBy.length > 1 ? "s" : ""} selected`
                : "All users"}
            </Button>
          </Popover.Target>
          <Popover.Dropdown p="xs">
            <Checkbox
              label="Select all"
              size="sm"
              fw={600}
              checked={filterPerformedBy.length === performedByOptions.length}
              indeterminate={
                filterPerformedBy.length > 0 &&
                filterPerformedBy.length < performedByOptions.length
              }
              onChange={() =>
                setFilterPerformedBy(
                  filterPerformedBy.length === performedByOptions.length
                    ? []
                    : performedByOptions.map((o) => o.value),
                )
              }
              mb={6}
            />
            <Divider mb={6} />
            <ScrollArea.Autosize mah={220}>
              <Stack gap={6}>
                {performedByOptions.map((opt) => (
                  <Checkbox
                    key={opt.value}
                    label={opt.label}
                    size="sm"
                    checked={filterPerformedBy.includes(opt.value)}
                    onChange={() =>
                      setFilterPerformedBy((prev) =>
                        prev.includes(opt.value)
                          ? prev.filter((v) => v !== opt.value)
                          : [...prev, opt.value],
                      )
                    }
                  />
                ))}
              </Stack>
            </ScrollArea.Autosize>
            {filterPerformedBy.length > 0 && (
              <Button
                size="xs"
                variant="subtle"
                color="gray"
                mt={6}
                fullWidth
                onClick={() => setFilterPerformedBy([])}
              >
                Clear all
              </Button>
            )}
          </Popover.Dropdown>
        </Popover>
        <DatePickerInput
          type="range"
          size="sm"
          placeholder="Pick date range"
          clearable
          leftSection={<IconCalendar size={16} />}
          value={filterDateRange}
          onChange={setFilterDateRange}
          maxDate={new Date()}
          valueFormat="DD MMM YYYY"
          style={{ width: 280 }}
        />
        <MRT_GlobalFilterTextInput
          table={table}
          variant="default"
          size="sm"
          leftSection={<IconSearch size={16} />}
          c="dark.8"
          p={0}
          style={{ flex: 1, minWidth: 200 }}
        />
        {hasActiveFilters && (
          <Group gap={6}>
            {filterEntity && (
              <Badge
                size="sm"
                variant="light"
                color="blue"
                rightSection={
                  <IconX
                    size={10}
                    style={{ cursor: "pointer" }}
                    onClick={() => setFilterEntity(null)}
                  />
                }
              >
                {filterEntity}
              </Badge>
            )}
            {filterAction && (
              <Badge
                size="sm"
                variant="light"
                color={ACTION_COLORS[filterAction] ?? "gray"}
                rightSection={
                  <IconX
                    size={10}
                    style={{ cursor: "pointer" }}
                    onClick={() => setFilterAction(null)}
                  />
                }
              >
                {filterAction}
              </Badge>
            )}
            {filterPerformedBy.length > 0 && (
              <Badge
                size="sm"
                variant="light"
                color="cyan"
                rightSection={
                  <IconX
                    size={10}
                    style={{ cursor: "pointer" }}
                    onClick={() => setFilterPerformedBy([])}
                  />
                }
              >
                {filterPerformedBy.length === 1
                  ? filterPerformedBy[0]
                  : `${filterPerformedBy.length} users`}
              </Badge>
            )}
            {(filterDateRange[0] || filterDateRange[1]) && (
              <Badge
                size="sm"
                variant="light"
                color="violet"
                rightSection={
                  <IconX
                    size={10}
                    style={{ cursor: "pointer" }}
                    onClick={() => setFilterDateRange([null, null])}
                  />
                }
              >
                {filterDateRange[0]
                  ? new Date(filterDateRange[0]).toLocaleDateString()
                  : "…"}{" "}
                –{" "}
                {filterDateRange[1]
                  ? new Date(filterDateRange[1]).toLocaleDateString()
                  : "…"}
              </Badge>
            )}
            <Text size="sm" c="dimmed">
              ({filteredData.length} result
              {filteredData.length !== 1 ? "s" : ""})
            </Text>
          </Group>
        )}
      </Group>

      <Paper
        bdrs={4}
        style={{
          overflow: "hidden",
          border: "1px solid var(--mantine-color-white-2)",
        }}
      >
        <Table
          fz={11}
          highlightOnHover
          horizontalSpacing="xl"
          verticalSpacing="xs"
          withColumnBorders
          m="0"
        >
          <Table.Thead>
            {table.getHeaderGroups().map((hg) => (
              <Table.Tr key={hg.id} c="dark.4" bg="gray.1">
                {hg.headers.map((header) => (
                  <Table.Th key={header.id} px={12}>
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.Header ??
                            header.column.columnDef.header,
                          header.getContext(),
                        )}
                  </Table.Th>
                ))}
              </Table.Tr>
            ))}
          </Table.Thead>
          <Table.Tbody>
            {table.getRowModel().rows.map((row) => (
              <Table.Tr
                key={row.id}
                style={{ cursor: "pointer" }}
                onClick={() => onRowClick(row.original)}
              >
                {row.getVisibleCells().map((cell) => (
                  <Table.Td key={cell.id} px={12}>
                    <MRT_TableBodyCellValue cell={cell} table={table} />
                  </Table.Td>
                ))}
              </Table.Tr>
            ))}
            {filteredData.length === 0 && (
              <Table.Tr>
                <Table.Td colSpan={99} ta="center" py="xl" c="dimmed">
                  No activity logs found.
                </Table.Td>
              </Table.Tr>
            )}
          </Table.Tbody>
        </Table>
      </Paper>

      <MRT_TablePagination table={table} />
    </Stack>
  );
};

export default HistoryClientPage;
