import { Anchor, Box, Group, HoverCard, Stack, Text } from "@mantine/core";
import { IconBrandJira, IconAlertCircle } from "@tabler/icons-react";
import { CSSProperties, useEffect, useState } from "react";
import * as api from "../api";
import type { CardJiraSyncState } from "../api";
import { formatDateTimeShort } from "./format";

// Adaptive polling: 5s steady-state, 1s while the card is mid-sync. The fast
// cadence catches the yellow → green transition right after a column drag;
// the slow cadence keeps the per-card load manageable when the board is idle.
const POLL_MS_STEADY = 5000;
const POLL_MS_INFLIGHT = 1000;

type Tone = "gray" | "yellow" | "green" | "red";

function tone(state: CardJiraSyncState): Tone {
  if (state.inflight) return "yellow";
  if (state.last_error) return "red";
  if (state.jira_key) return "green";
  return "gray";
}

const TONE_COLOR: Record<Tone, string> = {
  gray: "var(--mantine-color-gray-5)",
  yellow: "var(--mantine-color-yellow-5)",
  green: "var(--mantine-color-green-5)",
  red: "var(--mantine-color-red-6)",
};

const TONE_LABEL: Record<Tone, string> = {
  gray: "Sin sincronizar con Jira",
  yellow: "Sincronizando...",
  green: "Sincronizada con Jira",
  red: "Error de sincronizacion",
};

interface Props {
  cardId: string;
  // Pollen-down so the parent can refresh when needed (e.g. after a move
  // animation finishes) without waiting for the next tick.
  refreshTick?: number;
}

export function JiraSyncIndicator({ cardId, refreshTick }: Props) {
  const [state, setState] = useState<CardJiraSyncState | null>(null);
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    let timer: ReturnType<typeof setTimeout> | null = null;
    const schedule = (ms: number) => {
      if (cancelled) return;
      if (timer) clearTimeout(timer);
      timer = setTimeout(load, ms);
    };
    const load = async () => {
      try {
        const s = await api.getCardJiraSync(cardId);
        if (cancelled) return;
        setState(s);
        setErr(null);
        // Adaptive cadence: fast while the dispatcher is actively processing
        // this card, slow otherwise. Re-arms on every fetch so the moment
        // inflight flips off we drop back to the steady cadence.
        schedule(s.inflight ? POLL_MS_INFLIGHT : POLL_MS_STEADY);
      } catch (e) {
        if (cancelled) return;
        setErr((e as Error).message);
        schedule(POLL_MS_STEADY);
      }
    };
    // Window event fired by the App's drag-end handler so the indicator
    // refetches immediately after a move (and so the user sees yellow within
    // ~200ms instead of waiting up to POLL_MS_STEADY).
    const onMoved = (e: Event) => {
      const detail = (e as CustomEvent).detail as { cardId?: string } | undefined;
      if (detail?.cardId === cardId) {
        schedule(150);
      }
    };
    window.addEventListener("kanban-card-moved", onMoved);
    load();
    return () => {
      cancelled = true;
      if (timer) clearTimeout(timer);
      window.removeEventListener("kanban-card-moved", onMoved);
    };
  }, [cardId, refreshTick]);

  if (err && !state) {
    return (
      <Box title={err} style={dotStyle("var(--mantine-color-gray-3)")} aria-label="Jira sync state unavailable" />
    );
  }
  if (!state) {
    // Initial render — fade in a placeholder dot so the layout does not shift
    // when the fetch resolves.
    return <Box style={dotStyle("var(--mantine-color-gray-2)")} aria-label="Cargando estado Jira" />;
  }
  const t = tone(state);
  return (
    <HoverCard width={300} shadow="md" openDelay={150} closeDelay={120} withinPortal>
      <HoverCard.Target>
        <Box
          role="status"
          aria-label={TONE_LABEL[t]}
          onClick={(e) => e.stopPropagation()}
          onPointerDown={(e) => e.stopPropagation()}
          style={dotStyle(TONE_COLOR[t])}
        />
      </HoverCard.Target>
      <HoverCard.Dropdown onClick={(e) => e.stopPropagation()}>
        <Stack gap={6}>
          <Group gap={6} wrap="nowrap" justify="space-between">
            <Group gap={6} wrap="nowrap">
              <IconBrandJira size={14} />
              <Text size="sm" fw={600}>{TONE_LABEL[t]}</Text>
            </Group>
            {state.issue_url && (
              <Anchor
                size="xs"
                href={state.issue_url}
                target="_blank"
                rel="noopener noreferrer"
                onClick={(e) => e.stopPropagation()}
              >
                Abrir en Jira
              </Anchor>
            )}
          </Group>
          {state.jira_key && (
            <Text size="xs">
              <Text component="span" c="dimmed">Issue:</Text>{" "}
              <Text component="span" fw={600}>{state.jira_key}</Text>
            </Text>
          )}
          {state.last_status && (
            <Text size="xs">
              <Text component="span" c="dimmed">Status:</Text>{" "}
              <Text component="span">{state.last_status}</Text>
            </Text>
          )}
          {state.last_sync_at && (
            <Text size="xs">
              <Text component="span" c="dimmed">Ultimo sync:</Text>{" "}
              <Text component="span">{formatDateTimeShort(state.last_sync_at)}</Text>
            </Text>
          )}
          {state.last_error && (
            <Group gap={6} wrap="nowrap" align="flex-start">
              <IconAlertCircle size={14} color="var(--mantine-color-red-6)" />
              <Text size="xs" c="red" style={{ wordBreak: "break-word" }}>{state.last_error}</Text>
            </Group>
          )}
          {!state.jira_key && (
            <Text size="xs" c="dimmed">
              La card todavia no se ha empujado a Jira. Editala o muevela para
              disparar el sync, o usa la opcion "Importar de Jira" si ya existe
              alli.
            </Text>
          )}
        </Stack>
      </HoverCard.Dropdown>
    </HoverCard>
  );
}

function dotStyle(color: string): CSSProperties {
  return {
    width: 10,
    height: 10,
    borderRadius: "50%",
    background: color,
    cursor: "default",
    boxShadow: "0 0 0 2px var(--mantine-color-body)",
    transition: "background 120ms ease",
  };
}
