import { useState, useRef } from "react";
import { createPortal } from "react-dom";
import { format } from "date-fns";
import { motion, useReducedMotion, AnimatePresence } from "framer-motion";
import { fadeSlideUp, springs } from "@/lib/motion";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import type { Card, Label, Priority } from "@/types/board";
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
import { LabelDots } from "@/components/board/LabelDots";
import { ChecklistBar } from "@/components/board/ChecklistBar";
import { Paperclip, AlignLeft } from "lucide-react";
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSeparator,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu";
import { useBoardStore } from "@/stores/board-store";

/* ---------- Due date status ---------- */

function getDueDateStatus(dueDate: string | null): { color: string; bgColor: string; label: string } | null {
  if (!dueDate) return null;
  const date = new Date(dueDate);
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const dueDay = new Date(date.getFullYear(), date.getMonth(), date.getDate());
  const diffDays = Math.ceil((dueDay.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));

  if (diffDays < 0) {
    return { color: "text-pylon-danger", bgColor: "bg-pylon-danger/10", label: "Overdue" };
  }
  if (diffDays <= 2) {
    return { color: "text-[oklch(65%_0.15_70)]", bgColor: "bg-[oklch(65%_0.15_70/10%)]", label: "Due soon" };
  }
  return { color: "text-[oklch(55%_0.12_145)]", bgColor: "bg-[oklch(55%_0.12_145/10%)]", label: "Upcoming" };
}

/* ---------- Card aging ---------- */

function getAgingOpacity(updatedAt: string): number {
  const days = (Date.now() - new Date(updatedAt).getTime()) / (1000 * 60 * 60 * 24);
  if (days <= 7) return 1.0;
  if (days <= 14) return 0.85;
  if (days <= 30) return 0.7;
  return 0.55;
}

/* ---------- Priority colors ---------- */

const PRIORITY_COLORS: Record<string, string> = {
  low: "oklch(60% 0.15 240)",
  medium: "oklch(70% 0.15 85)",
  high: "oklch(60% 0.15 55)",
  urgent: "oklch(55% 0.15 25)",
};

interface CardThumbnailProps {
  card: Card;
  boardLabels: Label[];
  columnId: string;
  onCardClick?: (cardId: string) => void;
}

export function CardThumbnail({ card, boardLabels, columnId, onCardClick }: CardThumbnailProps) {
  const prefersReducedMotion = useReducedMotion();

  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({
    id: card.id,
    data: { type: "card", columnId },
  });

  const hasDueDate = card.dueDate != null;
  const dueDateStatus = getDueDateStatus(card.dueDate);

  function handleClick() {
    onCardClick?.(card.id);
  }

  // Drop indicator line when this card is being dragged
  if (isDragging) {
    return (
      <div
        ref={setNodeRef}
        style={{
          transform: CSS.Transform.toString(transform),
          transition,
        }}
        className="py-1"
        {...attributes}
        {...listeners}
      >
        <div className="h-[3px] rounded-full bg-pylon-accent shadow-[0_0_6px_var(--pylon-accent),0_0_14px_var(--pylon-accent)]" />
      </div>
    );
  }

  return (
    <ContextMenu>
      <ContextMenuTrigger asChild>
        <motion.button
          ref={setNodeRef}
          style={{
            transform: CSS.Transform.toString(transform),
            transition,
            padding: `calc(0.75rem * var(--density-factor))`,
            opacity: getAgingOpacity(card.updatedAt),
          }}
          onClick={handleClick}
          className="w-full rounded-lg bg-pylon-surface shadow-sm text-left"
          layoutId={`card-${card.id}`}
          variants={fadeSlideUp}
          initial={prefersReducedMotion ? false : "hidden"}
          animate="visible"
          whileHover={{ scale: 1.02, y: -2, boxShadow: "0 4px 12px oklch(0% 0 0 / 10%)" }}
          whileTap={{ scale: 0.98 }}
          transition={springs.bouncy}
          layout
          {...attributes}
          {...listeners}
          role="article"
          aria-label={card.title}
        >
          {/* Cover color bar */}
          {card.coverColor && (
            <div
              className="mb-2 h-1 rounded-t-lg"
              style={{
                backgroundColor: `oklch(55% 0.12 ${card.coverColor})`,
                margin: `calc(-0.75rem * var(--density-factor)) calc(-0.75rem * var(--density-factor)) 0.5rem`,
              }}
            />
          )}

          {/* Label dots */}
          {card.labels.length > 0 && (
            <div className="mb-2">
              <LabelDots labelIds={card.labels} boardLabels={boardLabels} />
            </div>
          )}

          {/* Card title */}
          <p className="text-sm font-medium text-pylon-text">{card.title}</p>

          {/* Footer row: priority + due date + checklist + icons */}
          {(hasDueDate || card.checklist.length > 0 || card.attachments.length > 0 || card.description || card.priority !== "none") && (
            <div className="mt-2 flex items-center gap-3">
              {card.priority !== "none" && (
                <span
                  className={`size-2.5 shrink-0 rounded-full ${card.priority === "urgent" ? "animate-pulse" : ""}`}
                  style={{ backgroundColor: PRIORITY_COLORS[card.priority] }}
                  title={`Priority: ${card.priority}`}
                />
              )}
              {dueDateStatus && card.dueDate && (
                <span
                  className={`font-mono text-xs rounded px-1 py-0.5 ${dueDateStatus.color} ${dueDateStatus.bgColor}`}
                  title={dueDateStatus.label}
                >
                  {format(new Date(card.dueDate), "MMM d")}
                </span>
              )}
              {card.checklist.length > 0 && (
                <ChecklistBar checklist={card.checklist} />
              )}
              {card.description && (
                <DescriptionPreview description={card.description} />
              )}
              {card.attachments.length > 0 && (
                <span className="flex items-center gap-0.5 text-pylon-text-secondary">
                  <Paperclip className="size-3" />
                  <span className="font-mono text-xs">{card.attachments.length}</span>
                </span>
              )}
            </div>
          )}
        </motion.button>
      </ContextMenuTrigger>
      <CardContextMenuContent cardId={card.id} columnId={columnId} />
    </ContextMenu>
  );
}

/* ---------- Card context menu ---------- */

function CardContextMenuContent({ cardId, columnId }: { cardId: string; columnId: string }) {
  const board = useBoardStore((s) => s.board);
  const moveCard = useBoardStore((s) => s.moveCard);
  const updateCard = useBoardStore((s) => s.updateCard);
  const duplicateCard = useBoardStore((s) => s.duplicateCard);
  const deleteCard = useBoardStore((s) => s.deleteCard);

  if (!board) return null;

  const otherColumns = board.columns.filter((c) => c.id !== columnId);
  const priorities: { value: Priority; label: string }[] = [
    { value: "none", label: "None" },
    { value: "low", label: "Low" },
    { value: "medium", label: "Medium" },
    { value: "high", label: "High" },
    { value: "urgent", label: "Urgent" },
  ];

  return (
    <ContextMenuContent>
      {otherColumns.length > 0 && (
        <ContextMenuSub>
          <ContextMenuSubTrigger>Move to</ContextMenuSubTrigger>
          <ContextMenuSubContent>
            {otherColumns.map((col) => (
              <ContextMenuItem
                key={col.id}
                onClick={() => moveCard(cardId, columnId, col.id, col.cardIds.length)}
              >
                {col.title}
              </ContextMenuItem>
            ))}
          </ContextMenuSubContent>
        </ContextMenuSub>
      )}
      <ContextMenuSub>
        <ContextMenuSubTrigger>Set priority</ContextMenuSubTrigger>
        <ContextMenuSubContent>
          {priorities.map(({ value, label }) => (
            <ContextMenuItem
              key={value}
              onClick={() => updateCard(cardId, { priority: value })}
            >
              {label}
            </ContextMenuItem>
          ))}
        </ContextMenuSubContent>
      </ContextMenuSub>
      <ContextMenuItem onClick={() => duplicateCard(cardId)}>
        Duplicate
      </ContextMenuItem>
      <ContextMenuSeparator />
      <ContextMenuItem
        variant="destructive"
        onClick={() => deleteCard(cardId)}
      >
        Delete
      </ContextMenuItem>
    </ContextMenuContent>
  );
}

/* ---------- Description hover preview ---------- */

function DescriptionPreview({ description }: { description: string }) {
  const [show, setShow] = useState(false);
  const [pos, setPos] = useState<{ below: boolean; top?: number; bottom?: number; left: number; arrowLeft: number; maxHeight: number } | null>(null);
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const iconRef = useRef<HTMLSpanElement>(null);

  function handleEnter() {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => {
      if (iconRef.current) {
        const rect = iconRef.current.getBoundingClientRect();
        const zoom = parseFloat(getComputedStyle(document.documentElement).fontSize) / 16;
        const popupW = 224 * zoom; // w-56 = 14rem, scales with zoom
        const gap = 8;

        // Flip below if more room below than above
        const titleBarH = 52 * zoom;
        const spaceAbove = rect.top - gap - titleBarH;
        const spaceBelow = window.innerHeight - rect.bottom - gap - 8;
        const below = spaceBelow > spaceAbove;

        // Max height for popup content (stay within viewport)
        const paddingPx = 24 * zoom; // p-3 top + bottom
        const maxAvailable = below
          ? window.innerHeight - (rect.bottom + gap) - 8
          : rect.top - gap - titleBarH;
        const maxHeight = Math.max(60, Math.min(maxAvailable - paddingPx, 300 * zoom));

        // Center horizontally, clamp to viewport
        let left = rect.left + rect.width / 2 - popupW / 2;
        left = Math.max(8, Math.min(left, window.innerWidth - popupW - 8));

        // Arrow offset relative to popup left edge
        const arrowLeft = Math.max(12, Math.min(rect.left + rect.width / 2 - left, popupW - 12));

        // Position: use top when below, bottom when above (avoids height estimation)
        setPos(below
          ? { below: true, top: rect.bottom + gap, left, arrowLeft, maxHeight }
          : { below: false, bottom: window.innerHeight - rect.top + gap, left, arrowLeft, maxHeight }
        );
      }
      setShow(true);
    }, 300);
  }

  function handleLeave() {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => setShow(false), 100);
  }

  function cancelHide() {
    if (timeoutRef.current) clearTimeout(timeoutRef.current);
  }

  // Strip markdown formatting for a clean preview
  const plainText = description
    .replace(/^#{1,6}\s+/gm, "")
    .replace(/\*\*(.+?)\*\*/g, "$1")
    .replace(/\*(.+?)\*/g, "$1")
    .replace(/`(.+?)`/g, "$1")
    .replace(/\[(.+?)\]\(.+?\)/g, "$1")
    .replace(/^[-*]\s+/gm, "- ")
    .trim();


  return (
    <span
      ref={iconRef}
      onMouseEnter={handleEnter}
      onMouseLeave={handleLeave}
    >
      <AlignLeft className="size-3 text-pylon-text-secondary" />
      {createPortal(
        <AnimatePresence>
          {show && pos && (
            <motion.div
              key="desc-preview"
              initial={{ opacity: 0, y: pos.below ? -4 : 4, scale: 0.95 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              exit={{ opacity: 0, y: pos.below ? -4 : 4, scale: 0.95 }}
              transition={{ duration: 0.15 }}
              className="pointer-events-auto fixed z-[9999] w-56 rounded-lg border border-border bg-pylon-surface p-3 shadow-xl"
              style={{
                ...(pos.below ? { top: pos.top } : { bottom: pos.bottom }),
                left: pos.left,
              }}
              onMouseEnter={cancelHide}
              onMouseLeave={() => setShow(false)}
              onClick={(e) => e.stopPropagation()}
            >
              {/* Arrow */}
              <div
                className={`absolute size-2 rotate-45 border-border bg-pylon-surface ${
                  pos.below ? "-top-1 border-l border-t" : "-bottom-1 border-b border-r"
                }`}
                style={{ left: pos.arrowLeft }}
              />
              <OverlayScrollbarsComponent
                style={{ maxHeight: pos.maxHeight }}
                options={{ scrollbars: { theme: "os-theme-pylon", autoHide: "scroll", autoHideDelay: 600, clickScroll: true }, overflow: { x: "hidden" } }}
                defer
              >
                <p className="whitespace-pre-wrap text-xs leading-relaxed text-pylon-text">
                  {plainText}
                </p>
              </OverlayScrollbarsComponent>
            </motion.div>
          )}
        </AnimatePresence>,
        document.body
      )}
    </span>
  );
}
