import { useMemo, useRef, useState } from "react";
import type { Hotspot } from "../types/annotations";
import { renderInlineMarkdown } from "../lib/markdownInline";

interface HotspotOverlayProps {
    hotspots: Hotspot[];
    currentFrame: number;
    editable?: boolean;
    selectedHotspotId?: string | null;
    onSelectHotspot?: (id: string) => void;
    onDeleteHotspot?: (id: string) => void;
    onUpdateHotspot?: (id: string, updater: (hotspot: Hotspot) => Hotspot) => void;
    onSeekToFrame?: (frame: number) => void;
    onNavigateToStep?: (
        destination: { type: "next_step" } | { type: "step"; stepId: string } | { type: "this_step" },
        hotspotId: string
    ) => void;
    onHotspotActivated?: (hotspotId: string) => void;
}

function HotspotOverlay({
    hotspots,
    currentFrame,
    editable = false,
    selectedHotspotId,
    onSeekToFrame,
    onSelectHotspot,
    onDeleteHotspot,
    onUpdateHotspot,
    onNavigateToStep,
    onHotspotActivated,
}: HotspotOverlayProps) {
    const [activeTooltipId, setActiveTooltipId] = useState<string | null>(null);
    const [hoveredId, setHoveredId] = useState<string | null>(null);
    const rootRef = useRef<HTMLDivElement | null>(null);
    const suppressClickRef = useRef(false);

    const clamp = (value: number, min: number, max: number) => Math.min(max, Math.max(min, value));

    const hexToRgba = (hex: string, alpha: number) => {
        const normalized = hex.trim().replace(/^#/, "");
        const safeAlpha = clamp(alpha, 0, 1);
        const normalizedHex =
            normalized.length === 3
                ? normalized
                      .split("")
                      .map((char) => `${char}${char}`)
                      .join("")
                : normalized;
        const parsed = Number.parseInt(normalizedHex, 16);
        if (normalizedHex.length !== 6 || Number.isNaN(parsed)) {
            return `rgba(11,16,32,${safeAlpha})`;
        }

        const r = (parsed >> 16) & 255;
        const g = (parsed >> 8) & 255;
        const b = parsed & 255;
        return `rgba(${r}, ${g}, ${b}, ${safeAlpha})`;
    };

    const spotlightRadius = (shape: Hotspot["spotlightShape"]) => {
        if (shape === "square") return "0px";
        if (shape === "circle") return "9999px";
        return "var(--radius-md)";
    };

    const clientToPercent = (clientX: number, clientY: number) => {
        const rect = rootRef.current?.getBoundingClientRect();
        if (!rect || rect.width <= 0 || rect.height <= 0) return null;
        const x = ((clientX - rect.left) / rect.width) * 100;
        const y = ((clientY - rect.top) / rect.height) * 100;
        return { x: clamp(x, 0, 100), y: clamp(y, 0, 100), rect };
    };

    const startMove = (event: React.PointerEvent, hotspot: Hotspot) => {
        if (!editable) return;
        if (!onUpdateHotspot) return;

        event.preventDefault();
        event.stopPropagation();
        onSelectHotspot?.(hotspot.id);

        const start = clientToPercent(event.clientX, event.clientY);
        if (!start) return;

        suppressClickRef.current = false;
        const startClientX = event.clientX;
        const startClientY = event.clientY;
        const offsetX = start.x - hotspot.x;
        const offsetY = start.y - hotspot.y;

        const onMove = (e: PointerEvent) => {
            const next = clientToPercent(e.clientX, e.clientY);
            if (!next) return;

            if (!suppressClickRef.current) {
                const dx = Math.abs(e.clientX - startClientX);
                const dy = Math.abs(e.clientY - startClientY);
                if (dx + dy > 3) suppressClickRef.current = true;
            }

            onUpdateHotspot(hotspot.id, (c) => {
                let x = next.x - offsetX;
                let y = next.y - offsetY;

                if (c.style === "rectangle") {
                    const halfW = Math.max(0.5, c.width / 2);
                    const halfH = Math.max(0.5, c.height / 2);
                    x = clamp(x, halfW, 100 - halfW);
                    y = clamp(y, halfH, 100 - halfH);
                } else {
                    x = clamp(x, 0, 100);
                    y = clamp(y, 0, 100);
                }

                return { ...c, x, y };
            });
        };

        const onUp = () => {
            window.removeEventListener("pointermove", onMove);
            window.removeEventListener("pointerup", onUp);
            window.removeEventListener("pointercancel", onUp);
        };

        window.addEventListener("pointermove", onMove);
        window.addEventListener("pointerup", onUp);
        window.addEventListener("pointercancel", onUp);
    };

    const startResizeArea = (
        event: React.PointerEvent,
        hotspot: Hotspot,
        corner: "tl" | "tr" | "bl" | "br"
    ) => {
        if (!editable) return;
        if (!onUpdateHotspot) return;
        if (hotspot.style !== "rectangle") return;

        event.preventDefault();
        event.stopPropagation();
        onSelectHotspot?.(hotspot.id);

        const start = clientToPercent(event.clientX, event.clientY);
        if (!start) return;

        suppressClickRef.current = false;
        const startClientX = event.clientX;
        const startClientY = event.clientY;

        const startLeft = hotspot.x - hotspot.width / 2;
        const startRight = hotspot.x + hotspot.width / 2;
        const startTop = hotspot.y - hotspot.height / 2;
        const startBottom = hotspot.y + hotspot.height / 2;

        const MIN_SIZE = 2; // percent

        const onMove = (e: PointerEvent) => {
            const next = clientToPercent(e.clientX, e.clientY);
            if (!next) return;

            if (!suppressClickRef.current) {
                const dx = Math.abs(e.clientX - startClientX);
                const dy = Math.abs(e.clientY - startClientY);
                if (dx + dy > 3) suppressClickRef.current = true;
            }

            let left = startLeft;
            let right = startRight;
            let top = startTop;
            let bottom = startBottom;

            if (corner === "tl" || corner === "bl") left = next.x;
            if (corner === "tr" || corner === "br") right = next.x;
            if (corner === "tl" || corner === "tr") top = next.y;
            if (corner === "bl" || corner === "br") bottom = next.y;

            left = clamp(left, 0, 100);
            right = clamp(right, 0, 100);
            top = clamp(top, 0, 100);
            bottom = clamp(bottom, 0, 100);

            // Enforce minimum size while keeping the opposite edge fixed.
            if (right - left < MIN_SIZE) {
                if (corner === "tl" || corner === "bl") {
                    left = right - MIN_SIZE;
                } else {
                    right = left + MIN_SIZE;
                }
                left = clamp(left, 0, 100);
                right = clamp(right, 0, 100);
            }
            if (bottom - top < MIN_SIZE) {
                if (corner === "tl" || corner === "tr") {
                    top = bottom - MIN_SIZE;
                } else {
                    bottom = top + MIN_SIZE;
                }
                top = clamp(top, 0, 100);
                bottom = clamp(bottom, 0, 100);
            }

            const width = clamp(right - left, MIN_SIZE, 100);
            const height = clamp(bottom - top, MIN_SIZE, 100);
            const x = clamp(left + width / 2, width / 2, 100 - width / 2);
            const y = clamp(top + height / 2, height / 2, 100 - height / 2);

            onUpdateHotspot(hotspot.id, (c) => ({ ...c, x, y, width, height, style: "rectangle" }));
        };

        const onUp = () => {
            window.removeEventListener("pointermove", onMove);
            window.removeEventListener("pointerup", onUp);
            window.removeEventListener("pointercancel", onUp);
        };

        window.addEventListener("pointermove", onMove);
        window.addEventListener("pointerup", onUp);
        window.addEventListener("pointercancel", onUp);
    };

    const visibleHotspots = useMemo(
        () =>
            hotspots.filter(
                (hotspot) => currentFrame >= hotspot.frameStart && currentFrame <= hotspot.frameEnd
            ),
        [currentFrame, hotspots]
    );

    return (
        <div
            ref={rootRef}
            style={{
                position: "absolute",
                top: 0,
                left: 0,
                width: "100%",
                height: "100%",
                pointerEvents: "none",
            }}
        >
            <style>{`
                @keyframes hotspot-pulse-ring {
                    0% { transform: scale(1); opacity: 0.35; }
                    70% { transform: scale(1.6); opacity: 0; }
                    100% { transform: scale(1.6); opacity: 0; }
                }
            `}</style>
            {visibleHotspots.map((hotspot) => {
                const isSelected = selectedHotspotId === hotspot.id;
                const isHovered = hoveredId === hotspot.id;
                const isTooltipVisible = activeTooltipId === hotspot.id;
                const baseColor = hotspot.backgroundColor ?? "#5E6AD2";
                const textColor = hotspot.textColor ?? "#FFFFFF";
                const isArea = hotspot.style === "rectangle";
                const isCallout = hotspot.style === "callout";
                const compactPercent = Math.max(0.6, Math.min(hotspot.width, hotspot.height));
                const compactSize = `clamp(14px, ${compactPercent}%, 24px)`;
                const ringColor =
                    isSelected || isHovered || editable
                        ? baseColor
                        : `color-mix(in srgb, ${baseColor} 80%, transparent)`;
                const displayText =
                    hotspot.text ?? (hotspot.action.type === "tooltip" ? hotspot.action.text : "");
                const showCallout = isCallout;
                const spotlightEnabled = Boolean(hotspot.spotlight && isArea);
                const spotlightOverlayColor = hotspot.spotlightOverlayColor ?? "#0B1020";
                const spotlightOverlayOpacity =
                    typeof hotspot.spotlightOverlayOpacity === "number"
                        ? clamp(hotspot.spotlightOverlayOpacity, 0, 0.9)
                        : 0.58;
                const spotlightBorderOpacity =
                    typeof hotspot.spotlightBorderOpacity === "number"
                        ? clamp(hotspot.spotlightBorderOpacity, 0.1, 1)
                        : 1;
                const spotlightShape = hotspot.spotlightShape ?? "rounded";
                const isDestinationAction =
                    hotspot.action.type === "next_step" ||
                    hotspot.action.type === "step" ||
                    hotspot.action.type === "this_step";

                return (
                    <div
                        key={hotspot.id}
                        onMouseEnter={() => setHoveredId(hotspot.id)}
                        onMouseLeave={() => setHoveredId(null)}
                        onClick={(event) => {
                            event.stopPropagation();
                            if (suppressClickRef.current) {
                                suppressClickRef.current = false;
                                return;
                            }
                            if (editable) {
                                onSelectHotspot?.(hotspot.id);
                                return;
                            }

                            onHotspotActivated?.(hotspot.id);

                            if (hotspot.action.type === "this_step") {
                                onNavigateToStep?.({ type: "this_step" }, hotspot.id);
                                return;
                            }

                            if (hotspot.action.type === "next_step") {
                                onNavigateToStep?.({ type: "next_step" }, hotspot.id);
                                return;
                            }

                            if (hotspot.action.type === "step") {
                                onNavigateToStep?.(hotspot.action, hotspot.id);
                                return;
                            }

                            if (hotspot.action.type === "seek") {
                                onSeekToFrame?.(hotspot.action.targetFrame);
                            } else if (hotspot.action.type === "url") {
                                window.open(
                                    hotspot.action.href,
                                    hotspot.action.newTab ? "_blank" : "_self",
                                    hotspot.action.newTab ? "noopener,noreferrer" : undefined
                                );
                            } else {
                                if (hotspot.style === "callout") return;
                                if (!displayText.trim()) return;
                                setActiveTooltipId((c) => (c === hotspot.id ? null : hotspot.id));
                            }
                        }}
                        style={{
                            position: "absolute",
                            left: `${hotspot.x}%`,
                            top: `${hotspot.y}%`,
                            width: isCallout ? "0px" : isArea ? `${hotspot.width}%` : compactSize,
                            height: isCallout ? "0px" : isArea ? `${hotspot.height}%` : compactSize,
                            transform: "translate(-50%, -50%)",
                            borderRadius: isArea ? spotlightRadius(spotlightShape) : "999px",
                            border: isCallout
                                ? "none"
                                : isArea
                                  ? isSelected
                                      ? `2px solid ${hexToRgba(baseColor, spotlightBorderOpacity)}`
                                      : isHovered || editable
                                        ? `1.5px solid ${hexToRgba(baseColor, spotlightBorderOpacity)}`
                                        : `1px solid ${hexToRgba(baseColor, spotlightBorderOpacity * 0.45)}`
                                  : `2px solid ${ringColor}`,
                            background: isCallout
                                ? "transparent"
                                : isArea
                                  ? isSelected
                                      ? `${hexToRgba(baseColor, 0.2)}`
                                      : isHovered
                                        ? `${hexToRgba(baseColor, 0.1)}`
                                        : "transparent"
                                  : "transparent",
                            cursor: editable ? "grab" : "pointer",
                            pointerEvents: "auto",
                            transition: "all 150ms var(--ease-out)",
                            boxShadow: isSelected && !isCallout ? "var(--shadow-glow)" : "none",
                            ...(spotlightEnabled
                                ? {
                                      boxShadow: `0 0 0 9999px ${hexToRgba(
                                          spotlightOverlayColor,
                                          spotlightOverlayOpacity
                                      )}`,
                                  }
                                : null),
                        }}
                        onPointerDown={(event) => {
                            if (!editable) return;
                            if (isCallout) return; // callout is dragged from its bubble
                            startMove(event, hotspot);
                        }}
                    >
                        {/* Inner dot for compact styles (Arcade-like) */}
                        {!isArea && !isCallout && (
                            <div
                                aria-hidden
                                style={{
                                    position: "absolute",
                                    left: "50%",
                                    top: "50%",
                                    transform: "translate(-50%, -50%)",
                                    width: "10px",
                                    height: "10px",
                                    borderRadius: "50%",
                                    border: `2px solid ${baseColor}`,
                                    background: "transparent",
                                    pointerEvents: "none",
                                }}
                            />
                        )}
                        {hotspot.style === "pulse" && !isCallout && (
                            <div
                                aria-hidden
                                style={{
                                    position: "absolute",
                                    inset: 0,
                                    borderRadius: "999px",
                                    border: `2px solid ${baseColor}`,
                                    opacity: 0.55,
                                    pointerEvents: "none",
                                    animation:
                                        editable || isSelected
                                            ? "none"
                                            : "hotspot-pulse-ring 1.6s ease-out infinite",
                                }}
                            />
                        )}

                        {/* Selection indicator - purple dot in corner when editing */}
                        {editable && !isSelected && !isCallout && (
                            <div
                                style={{
                                    position: "absolute",
                                    top: "-4px",
                                    right: "-4px",
                                    width: "8px",
                                    height: "8px",
                                    borderRadius: "50%",
                                    background: baseColor,
                                    boxShadow: "0 0 6px var(--accent-glow)",
                                }}
                            />
                        )}

                        {/* Selection handles - only when selected */}
                        {editable && isSelected && !isCallout && (
                            <>
                                {onDeleteHotspot && (
                                    <button
                                        aria-label="Delete hotspot"
                                        title="Delete hotspot"
                                        onPointerDown={(event) => {
                                            event.preventDefault();
                                            event.stopPropagation();
                                        }}
                                        onClick={(event) => {
                                            event.preventDefault();
                                            event.stopPropagation();
                                            onDeleteHotspot(hotspot.id);
                                        }}
                                        style={{
                                            position: "absolute",
                                            top: isArea ? "-16px" : "-18px",
                                            right: isArea ? "-16px" : "-18px",
                                            width: "26px",
                                            height: "26px",
                                            borderRadius: "999px",
                                            border: "none",
                                            background: "var(--status-danger)",
                                            color: "#fff",
                                            boxShadow: "0 8px 16px rgba(0,0,0,0.35)",
                                            display: "grid",
                                            placeItems: "center",
                                            cursor: "pointer",
                                            pointerEvents: "auto",
                                        }}
                                    >
                                        <svg
                                            width="12"
                                            height="12"
                                            viewBox="0 0 24 24"
                                            fill="none"
                                            stroke="currentColor"
                                            strokeWidth="2"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                        >
                                            <path d="M3 6h18" />
                                            <path d="M8 6V4h8v2" />
                                            <path d="M19 6l-1 14H6L5 6" />
                                            <path d="M10 11v6" />
                                            <path d="M14 11v6" />
                                        </svg>
                                    </button>
                                )}
                                {[
                                    {
                                        key: "tl" as const,
                                        top: -7,
                                        left: -7,
                                        cursor: "nwse-resize",
                                    },
                                    {
                                        key: "tr" as const,
                                        top: -7,
                                        right: -7,
                                        cursor: "nesw-resize",
                                    },
                                    {
                                        key: "bl" as const,
                                        bottom: -7,
                                        left: -7,
                                        cursor: "nesw-resize",
                                    },
                                    {
                                        key: "br" as const,
                                        bottom: -7,
                                        right: -7,
                                        cursor: "nwse-resize",
                                    },
                                ].map((pos) => (
                                    <div
                                        key={pos.key}
                                        onPointerDown={(event) => {
                                            if (!editable) return;
                                            if (!isArea) return;
                                            startResizeArea(event, hotspot, pos.key);
                                        }}
                                        style={{
                                            position: "absolute",
                                            ...pos,
                                            width: isArea ? "16px" : "8px",
                                            height: isArea ? "16px" : "8px",
                                            background: baseColor,
                                            borderRadius: isArea ? "999px" : "2px",
                                            boxShadow: isArea
                                                ? "0 3px 10px rgba(0,0,0,0.35)"
                                                : "0 1px 3px rgba(0,0,0,0.4)",
                                            cursor: isArea ? pos.cursor : "default",
                                            pointerEvents: isArea ? "auto" : "none",
                                        }}
                                    />
                                ))}
                            </>
                        )}

                        {/* Callout: always-visible bubble */}
                        {showCallout && (
                            <div
                                onPointerDown={(event) => {
                                    if (!editable) return;
                                    // Don't start drag if user interacted with the button area.
                                    const target = event.target as HTMLElement | null;
                                    if (target?.closest("button")) return;
                                    startMove(event, hotspot);
                                }}
                                style={{
                                    position: "absolute",
                                    // Position bubble below the pointer. The pointer triangle then
                                    // "connects" the bubble back to the hotspot coordinate.
                                    top: "10px",
                                    left: "50%",
                                    transform: "translateX(-50%)",
                                    minWidth: "220px",
                                    maxWidth: "340px",
                                    background: baseColor,
                                    color: textColor,
                                    padding: "14px",
                                    fontSize: "13px",
                                    lineHeight: 1.45,
                                    borderRadius: "14px",
                                    boxShadow: "0 16px 46px rgba(0,0,0,0.45)",
                                    zIndex: 100,
                                    pointerEvents: "auto",
                                    display: "flex",
                                    alignItems: "center",
                                    gap: "12px",
                                    cursor: editable
                                        ? "grab"
                                        : !editable && isDestinationAction
                                          ? "pointer"
                                          : "default",
                                }}
                            >
                                {isDestinationAction && (
                                    <button
                                        aria-label="Go to destination"
                                        style={{
                                            width: "40px",
                                            height: "40px",
                                            borderRadius: "12px",
                                            border: "none",
                                            background: "#fff",
                                            color: baseColor,
                                            boxShadow: "0 10px 22px rgba(0,0,0,0.22)",
                                            display: "grid",
                                            placeItems: "center",
                                            cursor:
                                                !editable && isDestinationAction
                                                    ? "pointer"
                                                    : "default",
                                        }}
                                    >
                                        <svg
                                            width="18"
                                            height="18"
                                            viewBox="0 0 24 24"
                                            fill="none"
                                            stroke="currentColor"
                                            strokeWidth="2"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                        >
                                            <path d="M5 12h12" />
                                            <path d="M13 6l6 6-6 6" />
                                        </svg>
                                    </button>
                                )}

                                {displayText.trim().length > 0 && (
                                    <div
                                        style={{
                                            flex: 1,
                                            minWidth: 0,
                                            whiteSpace: "pre-wrap",
                                            fontWeight: 650,
                                        }}
                                    >
                                        {renderInlineMarkdown(displayText)}
                                    </div>
                                )}
                                {editable && isSelected && onDeleteHotspot && (
                                    <button
                                        aria-label="Delete hotspot"
                                        title="Delete hotspot"
                                        onClick={(event) => {
                                            event.preventDefault();
                                            event.stopPropagation();
                                            onDeleteHotspot(hotspot.id);
                                        }}
                                        style={{
                                            width: "32px",
                                            height: "32px",
                                            borderRadius: "10px",
                                            border: "none",
                                            background: "rgba(0,0,0,0.24)",
                                            color: "#fff",
                                            display: "grid",
                                            placeItems: "center",
                                            cursor: "pointer",
                                            flexShrink: 0,
                                        }}
                                    >
                                        <svg
                                            width="14"
                                            height="14"
                                            viewBox="0 0 24 24"
                                            fill="none"
                                            stroke="currentColor"
                                            strokeWidth="2"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                        >
                                            <path d="M3 6h18" />
                                            <path d="M8 6V4h8v2" />
                                            <path d="M19 6l-1 14H6L5 6" />
                                            <path d="M10 11v6" />
                                            <path d="M14 11v6" />
                                        </svg>
                                    </button>
                                )}
                                <div
                                    aria-hidden
                                    style={{
                                        position: "absolute",
                                        bottom: "100%",
                                        left: "50%",
                                        transform: "translateX(-50%)",
                                        width: 0,
                                        height: 0,
                                        borderLeft: "8px solid transparent",
                                        borderRight: "8px solid transparent",
                                        borderBottom: `10px solid ${baseColor}`,
                                    }}
                                />
                            </div>
                        )}

                        {/* Tooltip */}
                        {!editable &&
                            hotspot.style !== "callout" &&
                            displayText.trim().length > 0 &&
                            isTooltipVisible && (
                                <div
                                    style={{
                                        position: "absolute",
                                        bottom: "calc(100% + 10px)",
                                        left: "50%",
                                        transform: "translateX(-50%)",
                                        whiteSpace: "pre-wrap",
                                        width: "max-content",
                                        maxWidth: "240px",
                                        background: "var(--bg-elevated)",
                                        border: "1px solid var(--border-default)",
                                        borderRadius: "var(--radius-lg)",
                                        color: "var(--text-primary)",
                                        padding: "10px 14px",
                                        fontSize: "13px",
                                        lineHeight: "1.5",
                                        boxShadow: "var(--shadow-lg)",
                                        zIndex: 100,
                                    }}
                                >
                                    {renderInlineMarkdown(displayText)}
                                </div>
                            )}
                    </div>
                );
            })}
        </div>
    );
}

export default HotspotOverlay;
