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;
