import { useSortable } from "@dnd-kit/sortable";
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import {
  ActionIcon,
  Badge,
  Box,
  Button,
  Group,
  Menu,
  NumberInput,
  Paper,
  Popover,
  ScrollArea,
  Select,
  Stack,
  Text,
  TextInput,
  Tooltip,
} from "@mantine/core";
import {
  IconArchive,
  IconArchiveOff,
  IconAlertTriangle,
  IconCheck,
  IconCheckbox,
  IconChevronDown,
  IconChevronRight,
  IconClock,
  IconDice5,
  IconDotsVertical,
  IconGripVertical,
  IconPencil,
  IconPlus,
  IconTrash,
  IconX,
} from "@tabler/icons-react";
import { memo, MouseEvent, useEffect, useMemo, useRef, useState } from "react";
import type { Card, CardColor, Column, User } from "../types";
import { KanbanCard } from "./KanbanCard";

type MaxTimeUnit = "minutes" | "hours" | "days" | "weeks" | "months";
const MAX_TIME_UNIT_MIN: Record<MaxTimeUnit, number> = {
  minutes: 1,
  hours: 60,
  days: 60 * 24,
  weeks: 60 * 24 * 7,
  months: 60 * 24 * 30,
};
const MAX_TIME_UNIT_LABEL: Record<MaxTimeUnit, string> = {
  minutes: "minutos",
  hours: "horas",
  days: "dias",
  weeks: "semanas",
  months: "meses",
};
const MAX_TIME_UNIT_SELECT_DATA = (Object.keys(MAX_TIME_UNIT_LABEL) as MaxTimeUnit[]).map((u) => ({
  value: u,
  label: MAX_TIME_UNIT_LABEL[u],
}));

interface Props {
  column: Column;
  cards: Card[];
  now: number;
  collapsed?: boolean;
  onAddCard: (columnId: string) => void;
  onRenameColumn: (id: string, name: string) => void;
  onResizeColumn: (id: string, width: number) => void;
  onMoveColumnLocation: (id: string, location: "board" | "sidebar") => void;
  onDeleteColumn: (id: string) => void;
  onSetWIPLimit: (id: string, limit: number) => void;
  onSetMaxTimeMinutes: (id: string, minutes: number) => void;
  onPickRandom: (columnId: string) => void;
  onToggleDone: (id: string, is_done: boolean) => void;
  onEditCard: (card: Card) => void;
  onDeleteCard: (id: string) => void;
  onDuplicateCard: (id: string) => void;
  onChangeCardColor: (id: string, color: CardColor) => void;
  onShowHistory: (card: Card) => void;
  onToggleCardLock: (id: string, locked: boolean) => void;
  onAssignCard: (id: string, assignee_id: string | null) => void;
  onSetCardDeadline?: (id: string, deadline: string | null) => void;
  onSetRequester?: (id: string, requester: string) => void;
  onArchiveCard?: (id: string) => void;
  requesterOptions?: string[];
  onOpenCustomCardColor?: (cardId: string, current: string) => void;
  activeSticker?: string | null;
  onAddSticker?: (cardId: string, x: number, y: number) => void;
  onRemoveSticker?: (cardId: string, index: number) => void;
  onMoveSticker?: (cardId: string, index: number, x: number, y: number) => void;
  onCommitSticker?: (cardId: string) => void;
  users: User[];
  usersById: Map<string, User>;
  highlightCardId?: string | null;
}

function KanbanColumnImpl({
  column,
  cards,
  now,
  collapsed,
  onAddCard,
  onRenameColumn,
  onResizeColumn,
  onMoveColumnLocation,
  onDeleteColumn,
  onSetWIPLimit,
  onSetMaxTimeMinutes,
  onPickRandom,
  onToggleDone,
  onEditCard,
  onDeleteCard,
  onDuplicateCard,
  onChangeCardColor,
  onShowHistory,
  onToggleCardLock,
  onAssignCard,
  onSetCardDeadline,
  onSetRequester,
  onArchiveCard,
  requesterOptions,
  onOpenCustomCardColor,
  activeSticker,
  onAddSticker,
  onRemoveSticker,
  onMoveSticker,
  onCommitSticker,
  users,
  usersById,
  highlightCardId,
}: Props) {
  const [renaming, setRenaming] = useState(false);
  const [name, setName] = useState(column.name);
  const [localWidth, setLocalWidth] = useState<number | null>(null);
  const [wipPopOpen, setWipPopOpen] = useState(false);
  const [wipDraft, setWipDraft] = useState<number | string>(column.wip_limit);
  const [maxTimePopOpen, setMaxTimePopOpen] = useState(false);
  // Initial unit picked from current value: largest unit that yields >=1
  const pickInitialUnit = (mins: number): MaxTimeUnit => {
    if (mins <= 0) return "minutes";
    if (mins % 43200 === 0) return "months";
    if (mins % 10080 === 0) return "weeks";
    if (mins % 1440 === 0) return "days";
    if (mins % 60 === 0) return "hours";
    return "minutes";
  };
  const minutesToUnit = (mins: number, u: MaxTimeUnit): number => {
    const div = MAX_TIME_UNIT_MIN[u];
    return mins > 0 ? Math.max(1, Math.round(mins / div)) : 0;
  };
  const [maxTimeUnit, setMaxTimeUnit] = useState<MaxTimeUnit>(() => pickInitialUnit(column.max_time_minutes || 0));
  const [maxTimeDraft, setMaxTimeDraft] = useState<number | string>(() =>
    minutesToUnit(column.max_time_minutes || 0, pickInitialUnit(column.max_time_minutes || 0))
  );
  const [bodyHidden, setBodyHidden] = useState(() => {
    if (!collapsed) return false;
    return localStorage.getItem(`kanban_col_body_${column.id}`) === "1";
  });
  useEffect(() => {
    if (collapsed) {
      localStorage.setItem(`kanban_col_body_${column.id}`, bodyHidden ? "1" : "0");
    }
  }, [bodyHidden, collapsed, column.id]);

  const wipLimit = column.wip_limit;
  const overLimit = wipLimit > 0 && cards.length > wipLimit;

  // sync local width when column.width changes from outside (other clients).
  useEffect(() => {
    setLocalWidth(null);
  }, [column.width]);

  const sortableData = useMemo(
    () => ({ type: "column" as const, columnId: column.id, location: column.location }),
    [column.id, column.location]
  );
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: `column-${column.id}`,
    data: sortableData,
  });

  const effectiveWidth = collapsed ? "100%" : localWidth ?? column.width;

  const style: React.CSSProperties = collapsed
    ? {
        transform: CSS.Transform.toString(transform),
        transition,
        opacity: isDragging ? 0.4 : 1,
        width: "100%",
        display: "flex",
        flexDirection: "column",
        position: "relative",
        flex: bodyHidden ? "0 0 auto" : "1 1 auto",
        minHeight: 0,
      }
    : {
        transform: CSS.Transform.toString(transform),
        transition,
        opacity: isDragging ? 0.4 : 1,
        width: effectiveWidth,
        minWidth: effectiveWidth,
        maxWidth: effectiveWidth,
        display: "flex",
        flexDirection: "column",
        height: "100%",
        position: "relative",
      };

  const cardIds = cards.map((c) => c.id);

  const submitRename = () => {
    const trimmed = name.trim();
    if (trimmed && trimmed !== column.name) onRenameColumn(column.id, trimmed);
    setRenaming(false);
  };

  // --- resize handle ---
  const resizingRef = useRef<{ startX: number; startWidth: number } | null>(null);

  const onResizeMouseDown = (e: MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    resizingRef.current = { startX: e.clientX, startWidth: column.width };
    document.body.style.cursor = "col-resize";
    document.body.style.userSelect = "none";
    const onMove = (ev: globalThis.MouseEvent) => {
      if (!resizingRef.current) return;
      const dx = ev.clientX - resizingRef.current.startX;
      const next = Math.min(800, Math.max(200, resizingRef.current.startWidth + dx));
      setLocalWidth(next);
    };
    const onUp = () => {
      if (resizingRef.current && localWidthRef.current !== null) {
        onResizeColumn(column.id, localWidthRef.current);
      }
      resizingRef.current = null;
      document.body.style.cursor = "";
      document.body.style.userSelect = "";
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
    };
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
  };

  // mirror localWidth into a ref so the mouseup handler always sees the latest value.
  const localWidthRef = useRef<number | null>(null);
  useEffect(() => {
    localWidthRef.current = localWidth;
  }, [localWidth]);

  const isInSidebar = column.location === "sidebar";
  const archiveLabel = isInSidebar ? "Restaurar al board" : "Mover al sidebar";
  const ArchiveIcon = isInSidebar ? IconArchiveOff : IconArchive;

  const submitWIP = () => {
    const n = typeof wipDraft === "number" ? wipDraft : parseInt(String(wipDraft), 10);
    const safe = Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
    if (safe !== column.wip_limit) onSetWIPLimit(column.id, safe);
    setWipPopOpen(false);
  };

  const paperBg = overLimit ? "var(--mantine-color-red-9)" : "var(--mantine-color-dark-7)";
  const paperBorderColor = overLimit ? "var(--mantine-color-red-6)" : undefined;

  return (
    <Paper
      ref={setNodeRef}
      style={{ ...style, background: paperBg, borderColor: paperBorderColor, borderWidth: overLimit ? 2 : 1 }}
      withBorder
      radius="md"
      p="sm"
      data-column-id={column.id}
      data-column-location={column.location}
    >
      <Group justify="space-between" mb="xs" wrap="nowrap">
        <Group gap={4} wrap="nowrap" style={{ flex: 1, minWidth: 0 }}>
          <ActionIcon
            variant="subtle"
            color="gray"
            size="sm"
            {...attributes}
            {...listeners}
            style={{ cursor: "grab" }}
            aria-label="Drag column"
          >
            <IconGripVertical size={14} />
          </ActionIcon>
          {renaming ? (
            <TextInput
              size="xs"
              value={name}
              onChange={(e) => setName(e.currentTarget.value)}
              autoFocus
              onBlur={submitRename}
              onKeyDown={(e) => {
                if (e.key === "Enter") submitRename();
                if (e.key === "Escape") {
                  setName(column.name);
                  setRenaming(false);
                }
              }}
              style={{ flex: 1 }}
            />
          ) : (
            <Text
              fw={600}
              size="sm"
              truncate
              onDoubleClick={() => {
                setName(column.name);
                setRenaming(true);
              }}
              style={{ flex: 1, cursor: "text" }}
              title="Doble click para renombrar"
            >
              {column.name}
            </Text>
          )}
          <Popover
            opened={wipPopOpen}
            onChange={(o) => {
              setWipPopOpen(o);
              if (o) setWipDraft(column.wip_limit);
            }}
            position="bottom"
            withArrow
            shadow="md"
          >
            <Popover.Target>
              <Tooltip
                label={
                  wipLimit > 0
                    ? `WIP ${cards.length}/${wipLimit}${overLimit ? " (excedido)" : ""}`
                    : "Click para limitar WIP"
                }
                withArrow
              >
                <Badge
                  size="xs"
                  variant={overLimit ? "filled" : "light"}
                  color={overLimit ? "red" : wipLimit > 0 ? "yellow" : "gray"}
                  leftSection={overLimit ? <IconAlertTriangle size={10} /> : null}
                  style={{ cursor: "pointer" }}
                  onClick={() => setWipPopOpen((v) => !v)}
                >
                  {wipLimit > 0 ? `${cards.length}/${wipLimit}` : cards.length}
                </Badge>
              </Tooltip>
            </Popover.Target>
            <Popover.Dropdown p="xs">
              <Stack gap="xs">
                <Text size="xs" c="dimmed">
                  Maximo de tarjetas (0 = sin limite)
                </Text>
                <NumberInput
                  size="xs"
                  value={wipDraft}
                  onChange={setWipDraft}
                  min={0}
                  max={999}
                  autoFocus
                  onKeyDown={(e) => {
                    if (e.key === "Enter") submitWIP();
                    if (e.key === "Escape") setWipPopOpen(false);
                  }}
                />
                <Group justify="flex-end" gap={4}>
                  <Button size="xs" variant="subtle" onClick={() => setWipPopOpen(false)}>
                    Cancelar
                  </Button>
                  <Button size="xs" onClick={submitWIP}>
                    Guardar
                  </Button>
                </Group>
              </Stack>
            </Popover.Dropdown>
          </Popover>
        </Group>
        <Group gap={2} wrap="nowrap">
          {renaming ? (
            <>
              <ActionIcon variant="subtle" color="green" size="sm" onClick={submitRename} aria-label="Save">
                <IconCheck size={14} />
              </ActionIcon>
              <ActionIcon
                variant="subtle"
                color="gray"
                size="sm"
                onClick={() => {
                  setName(column.name);
                  setRenaming(false);
                }}
                aria-label="Cancel"
              >
                <IconX size={14} />
              </ActionIcon>
            </>
          ) : (
            <>
              {collapsed && (
                <Tooltip label={bodyHidden ? "Expandir" : "Colapsar"} withArrow>
                  <ActionIcon
                    variant="subtle"
                    color="gray"
                    size="sm"
                    onClick={() => setBodyHidden((v) => !v)}
                    aria-label={bodyHidden ? "Expandir columna" : "Colapsar columna"}
                  >
                    {bodyHidden ? <IconChevronRight size={14} /> : <IconChevronDown size={14} />}
                  </ActionIcon>
                </Tooltip>
              )}
              {column.is_done && (
                <Tooltip label="Columna Done" withArrow>
                  <Badge size="xs" color="green" variant="filled" leftSection={<IconCheckbox size={10} />}>
                    done
                  </Badge>
                </Tooltip>
              )}
              <Menu position="bottom-end" shadow="md" withArrow>
                <Menu.Target>
                  <ActionIcon variant="subtle" color="gray" size="sm" aria-label="Acciones columna">
                    <IconDotsVertical size={14} />
                  </ActionIcon>
                </Menu.Target>
                <Menu.Dropdown>
                  <Menu.Label>Columna</Menu.Label>
                  <Menu.Item
                    leftSection={<IconPencil size={14} />}
                    onClick={() => {
                      setName(column.name);
                      setRenaming(true);
                    }}
                  >
                    Renombrar
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<IconCheckbox size={14} />}
                    color={column.is_done ? "yellow" : "green"}
                    onClick={() => onToggleDone(column.id, !column.is_done)}
                  >
                    {column.is_done ? "Quitar marca Done" : "Marcar como Done"}
                  </Menu.Item>
                  <Popover
                    opened={maxTimePopOpen}
                    onChange={(o) => {
                      setMaxTimePopOpen(o);
                      if (o) {
                        const u = pickInitialUnit(column.max_time_minutes || 0);
                        setMaxTimeUnit(u);
                        setMaxTimeDraft(minutesToUnit(column.max_time_minutes || 0, u));
                      }
                    }}
                    position="right-start"
                    withArrow
                    shadow="md"
                    withinPortal={false}
                  >
                    <Popover.Target>
                      <Menu.Item
                        leftSection={<IconClock size={14} />}
                        data-test="column-max-time"
                        closeMenuOnClick={false}
                        onClick={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                          setMaxTimePopOpen((v) => !v);
                        }}
                      >
                        Tiempo maximo
                        {column.max_time_minutes > 0
                          ? ` (${(() => {
                              const u = pickInitialUnit(column.max_time_minutes);
                              return `${minutesToUnit(column.max_time_minutes, u)} ${MAX_TIME_UNIT_LABEL[u]}`;
                            })()})`
                          : ""}
                      </Menu.Item>
                    </Popover.Target>
                    <Popover.Dropdown
                      p="xs"
                      onClick={(e) => e.stopPropagation()}
                      onMouseDown={(e) => e.stopPropagation()}
                      onDoubleClick={(e) => e.stopPropagation()}
                    >
                      <Stack gap={6} style={{ minWidth: 240 }}>
                        <Text size="xs" c="dimmed">
                          Cards que pasen este tiempo se pintaran con borde rojo. 0 = sin limite. Columnas Done no aplican.
                        </Text>
                        <Group gap={6} wrap="nowrap">
                          <NumberInput
                            size="xs"
                            min={0}
                            max={999}
                            value={maxTimeDraft}
                            onChange={setMaxTimeDraft}
                            placeholder="0"
                            style={{ width: 90 }}
                            data-test="column-max-time-input"
                          />
                          <Select
                            size="xs"
                            value={maxTimeUnit}
                            onChange={(v) => v && setMaxTimeUnit(v as MaxTimeUnit)}
                            data={MAX_TIME_UNIT_SELECT_DATA}
                            style={{ width: 130 }}
                            allowDeselect={false}
                            data-test="column-max-time-unit"
                          />
                        </Group>
                        <Group justify="space-between" gap={6}>
                          <Tooltip label="Quitar limite" withArrow disabled={!column.max_time_minutes}>
                            <ActionIcon
                              size="sm"
                              variant="subtle"
                              color="red"
                              disabled={!column.max_time_minutes}
                              onClick={() => {
                                onSetMaxTimeMinutes(column.id, 0);
                                setMaxTimeDraft(0);
                                setMaxTimePopOpen(false);
                              }}
                            >
                              <IconTrash size={12} />
                            </ActionIcon>
                          </Tooltip>
                          <Button
                            size="xs"
                            data-test="column-max-time-save"
                            onClick={() => {
                              const raw =
                                typeof maxTimeDraft === "number"
                                  ? maxTimeDraft
                                  : parseInt(String(maxTimeDraft), 10);
                              const n = Number.isFinite(raw) && raw >= 0 ? raw : 0;
                              const mins = n * MAX_TIME_UNIT_MIN[maxTimeUnit];
                              if (mins !== column.max_time_minutes) {
                                onSetMaxTimeMinutes(column.id, mins);
                              }
                              setMaxTimePopOpen(false);
                            }}
                          >
                            Guardar
                          </Button>
                        </Group>
                      </Stack>
                    </Popover.Dropdown>
                  </Popover>
                  {!column.is_done && (
                    <Menu.Item
                      leftSection={<IconDice5 size={14} />}
                      data-test="column-random-pick"
                      disabled={cards.filter((c) => !c.locked).length === 0}
                      onClick={() => onPickRandom(column.id)}
                    >
                      Seleccionar Aleatorio
                    </Menu.Item>
                  )}
                  <Menu.Item
                    leftSection={<ArchiveIcon size={14} />}
                    onClick={() => onMoveColumnLocation(column.id, isInSidebar ? "board" : "sidebar")}
                  >
                    {archiveLabel}
                  </Menu.Item>
                  <Menu.Divider />
                  <Menu.Item
                    leftSection={<IconTrash size={14} />}
                    color="red"
                    onClick={() => onDeleteColumn(column.id)}
                  >
                    Borrar columna
                  </Menu.Item>
                </Menu.Dropdown>
              </Menu>
            </>
          )}
        </Group>
      </Group>

      {!(collapsed && bodyHidden) && (
        <>
          <ScrollArea style={{ flex: 1 }} type="auto">
            <SortableContext items={cardIds} strategy={verticalListSortingStrategy}>
              <Stack gap="xs" pb="xs" style={{ minHeight: 40 }}>
                {cards.map((c) => (
                  <KanbanCard
                    key={c.id}
                    card={c}
                    now={now}
                    onDelete={onDeleteCard}
                    onEdit={onEditCard}
                    onDuplicate={onDuplicateCard}
                    onChangeColor={onChangeCardColor}
                    onShowHistory={onShowHistory}
                    onToggleLock={onToggleCardLock}
                    onAssign={onAssignCard}
                    onSetDeadline={onSetCardDeadline}
                    onSetRequester={onSetRequester}
                    onArchive={onArchiveCard}
                    requesterOptions={requesterOptions}
                    onOpenCustomColor={onOpenCustomCardColor}
                    users={users}
                    assignee={c.assignee_id ? usersById.get(c.assignee_id) : undefined}
                    inDoneColumn={column.is_done}
                    columnOverdue={
                      !column.is_done &&
                      column.max_time_minutes > 0 &&
                      c.time_in_column_ms > column.max_time_minutes * 60_000
                    }
                    highlight={highlightCardId === c.id}
                    activeSticker={activeSticker}
                    onAddSticker={onAddSticker}
                    onRemoveSticker={onRemoveSticker}
                    onMoveSticker={onMoveSticker}
                    onCommitSticker={onCommitSticker}
                  />
                ))}
              </Stack>
            </SortableContext>
          </ScrollArea>

          <Button
            variant="subtle"
            color="gray"
            size="xs"
            leftSection={<IconPlus size={14} />}
            onClick={() => onAddCard(column.id)}
            mt="xs"
            fullWidth
            data-test="add-card"
          >
            Anadir tarjeta
          </Button>
        </>
      )}

      {/* Resize handle (only on board, not sidebar) */}
      {!isInSidebar && (
        <Box
          onMouseDown={onResizeMouseDown}
          style={{
            position: "absolute",
            top: 0,
            right: -3,
            width: 6,
            height: "100%",
            cursor: "col-resize",
            zIndex: 5,
          }}
          aria-label="Resize column"
        />
      )}
    </Paper>
  );
}

export const KanbanColumn = memo(KanbanColumnImpl);
