"use client";

import {
  Alert,
  Badge,
  Box,
  Button,
  Chip,
  Collapse,
  Divider,
  Group,
  Loader,
  Paper,
  Stack,
  Text,
  ThemeIcon,
  Tooltip,
  UnstyledButton,
} from "@mantine/core";
import {
  IconAlertCircle,
  IconChevronDown,
  IconPlayerPlay,
  IconRefresh,
} from "@tabler/icons-react";
import { useMemo, useState } from "react";
import { checks } from "./registry";
import { ResultDetail, STATUS_META, type StageStatus } from "./ResultDetail";
import type { CheckResult, CheckStatus, TemplateContext } from "./types";

interface Props {
  template: {
    name: string;
    subject: string;
    htmlContent: string;
    plainContent: string;
  };
  canRun?: boolean;
}

const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));

export function TestFlowPanel({ template, canRun = true }: Props) {
  const allIds = useMemo(() => checks.map((c) => c.id), []);
  const [selected, setSelected] = useState<string[]>(allIds);
  const [results, setResults] = useState<Record<string, CheckResult>>({});
  const [stageStatus, setStageStatus] = useState<Record<string, StageStatus>>({});
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
  const [running, setRunning] = useState(false);

  const stages = checks.filter((c) => selected.includes(c.id));

  const runPipeline = async () => {
    setRunning(true);
    setResults({});
    setExpanded(new Set());
    setStageStatus(Object.fromEntries(stages.map((c) => [c.id, "pending"])));

    const doc = new DOMParser().parseFromString(template.htmlContent || "", "text/html");
    const ctx: TemplateContext = { ...template, doc };

    const autoExpand = new Set<string>();
    for (const c of stages) {
      setStageStatus((prev) => ({ ...prev, [c.id]: "running" }));
      await sleep(260);
      const result = await c.run(ctx);
      setResults((prev) => ({ ...prev, [c.id]: result }));
      setStageStatus((prev) => ({ ...prev, [c.id]: result.status }));
      if (result.status !== "pass") autoExpand.add(c.id);
    }
    setExpanded(autoExpand);
    setRunning(false);
  };

  const toggle = (id: string) =>
    setExpanded((prev) => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });

  const counts = Object.values(results).reduce(
    (acc, r) => ({ ...acc, [r.status]: acc[r.status] + 1 }),
    { pass: 0, warning: 0, fail: 0 } as Record<CheckStatus, number>,
  );
  const hasResults = Object.keys(results).length > 0;
  const allSelected = selected.length === allIds.length;
  const noneSelected = selected.length === 0;

  return (
    <Stack gap="md">
      {/* Config card */}
      <Paper withBorder radius="md" p="md">
        <Group justify="space-between" align="flex-start" mb="xs" wrap="nowrap">
          <div>
            <Text fw={600} size="sm">QA Checks</Text>
            <Text size="xs" c="dimmed">
              Select the checks to run. Everything runs in your browser — nothing is sent or saved.
            </Text>
          </div>
          <Group gap="xs" wrap="nowrap">
            <Tooltip label="Select all checks" position="top" withArrow>
              <Button
                variant={allSelected ? "filled" : "light"}
                color="blue"
                size="xs"
                onClick={() => setSelected(allIds)}
                disabled={running || allSelected}
              >
                All
              </Button>
            </Tooltip>
            <Tooltip label="Deselect all checks" position="top" withArrow>
              <Button
                variant="light"
                color="gray"
                size="xs"
                onClick={() => setSelected([])}
                disabled={running || noneSelected}
              >
                Deselect
              </Button>
            </Tooltip>
          </Group>
        </Group>

        <Chip.Group multiple value={selected} onChange={setSelected}>
          <Group gap="xs">
            {checks.map((c) => (
              <Tooltip
                key={c.id}
                label={c.description}
                position="top"
                withArrow
                multiline
                w={260}
              >
                <Chip value={c.id} size="sm" variant="light" disabled={running}>
                  {c.label}
                </Chip>
              </Tooltip>
            ))}
          </Group>
        </Chip.Group>

        {!template.htmlContent && (
          <Alert color="orange" icon={<IconAlertCircle size={16} />} variant="light" mt="sm">
            No HTML content yet — checks will run against an empty document.
          </Alert>
        )}

        <Divider my="sm" />

        <Group justify="space-between" align="center">
          <Group gap="xs">
            {hasResults ? (
              <>
                {counts.pass > 0 && (
                  <Badge color="green" variant="light" size="sm">{counts.pass} Passed</Badge>
                )}
                {counts.warning > 0 && (
                  <Badge color="yellow" variant="light" size="sm">{counts.warning} Warning{counts.warning !== 1 ? "s" : ""}</Badge>
                )}
                {counts.fail > 0 && (
                  <Badge color="red" variant="light" size="sm">{counts.fail} Failed</Badge>
                )}
              </>
            ) : (
              <Text size="xs" c="dimmed">
                {selected.length} of {checks.length} check{checks.length !== 1 ? "s" : ""} selected
              </Text>
            )}
          </Group>
          <Button
            leftSection={hasResults ? <IconRefresh size={15} /> : <IconPlayerPlay size={15} />}
            size="sm"
            onClick={runPipeline}
            loading={running}
            disabled={selected.length === 0}
          >
            {hasResults ? "Re-run" : "Run checks"}
          </Button>
        </Group>
      </Paper>

      {/* Pipeline */}
      {stages.length > 0 && (
        <Stack gap={0}>
          {stages.map((c, idx) => {
            const status: StageStatus = stageStatus[c.id] ?? "pending";
            const meta = STATUS_META[status];
            const StatusIcon = meta.icon;
            const result = results[c.id];
            const isLast = idx === stages.length - 1;
            const isOpen = expanded.has(c.id);

            return (
              <Group key={c.id} wrap="nowrap" align="stretch" gap="sm">
                {/* Timeline node + connector */}
                <Stack align="center" gap={0} style={{ width: 28, flexShrink: 0 }}>
                  <ThemeIcon radius="xl" size={28} color={meta.color} variant="light">
                    {status === "running" ? (
                      <Loader size={13} color={meta.color} />
                    ) : (
                      <StatusIcon size={15} />
                    )}
                  </ThemeIcon>
                  {!isLast && (
                    <Box
                      style={{
                        flex: 1,
                        width: 2,
                        minHeight: 12,
                        background: "var(--mantine-color-gray-3)",
                      }}
                    />
                  )}
                </Stack>

                {/* Stage card */}
                <Box style={{ flex: 1, minWidth: 0, paddingBottom: isLast ? 0 : 10 }}>
                  <Paper
                    withBorder
                    radius="md"
                    p="sm"
                    style={{
                      borderLeft: `3px solid var(--mantine-color-${meta.color}-${status === "pending" ? "2" : "5"})`,
                      opacity: status === "pending" ? 0.65 : 1,
                      transition: "opacity 200ms, border-color 200ms",
                    }}
                  >
                    <UnstyledButton
                      onClick={() => result && toggle(c.id)}
                      style={{ width: "100%", cursor: result ? "pointer" : "default" }}
                    >
                      <Group justify="space-between" wrap="nowrap" align="center">
                        <Stack gap={0} style={{ minWidth: 0 }}>
                          <Text size="sm" fw={600} lh={1.3}>{c.label}</Text>
                          <Text size="xs" c="dimmed" lineClamp={1} lh={1.4}>{c.description}</Text>
                        </Stack>
                        <Group gap="xs" wrap="nowrap" style={{ flexShrink: 0 }}>
                          <Badge color={meta.color} variant="light" size="sm">{meta.label}</Badge>
                          {result && (
                            <IconChevronDown
                              size={15}
                              style={{
                                transition: "transform 150ms",
                                transform: isOpen ? "rotate(180deg)" : "none",
                                color: "var(--mantine-color-dimmed)",
                              }}
                            />
                          )}
                        </Group>
                      </Group>
                    </UnstyledButton>
                    {result && (
                      <Collapse in={isOpen}>
                        <Box pt="xs">
                          <ResultDetail result={result} />
                        </Box>
                      </Collapse>
                    )}
                  </Paper>
                </Box>
              </Group>
            );
          })}
        </Stack>
      )}
    </Stack>
  );
}
