import { useEffect, useMemo, useRef, useState, type PointerEvent, type ReactNode, type RefObject } from "react";
import {
    ChevronDown,
    FolderPlus,
    LocateFixed,
    Move,
    Plus,
    RefreshCw,
    Save,
    Search,
    Settings2,
    X,
    ZoomIn,
    ZoomOut,
} from "lucide-react";

import satelliteImage from "../../../assets/sattelite169.png";
import { useSynopticVariables } from "../hooks/useSynopticVariables";
import type { SynopticVariable } from "../hooks/useSynopticVariables";

type SynopticPageProps = {
    theme: "dark" | "light";
};

type CardVariant = "compact" | "large";

type MapItem = {
    id: string;
    variableId: string;
    x: number;
    y: number;
    variant: CardVariant;
    showLabel: boolean;
};

const initialMapItems: MapItem[] = [];

export function SynopticPage({ theme }: SynopticPageProps) {
    const isDark = theme === "dark";
    const canvasRef = useRef<HTMLDivElement | null>(null);
    const synoptic = useSynopticVariables();

    const [items, setItems] = useState<MapItem[]>(initialMapItems);
    const [selectedItemId, setSelectedItemId] = useState<string | null>(null);
    const [activeGroup, setActiveGroup] = useState<string>("Todas");
    const [search, setSearch] = useState("");

    const [pendingVariableDrag, setPendingVariableDrag] = useState<{
        id: string;
        pointerId: number;
    } | null>(null);

    const [dragState, setDragState] = useState<{
        id: string;
        pointerId: number;
        offsetX: number;
        offsetY: number;
    } | null>(null);

    const variablesById = useMemo(
        () =>
            new Map(
                synoptic.variables.map((variable) => [
                    variable.id,
                    variable,
                ]),
            ),
        [synoptic.variables],
    );

    const selectedItem =
        items.find((item) => item.id === selectedItemId) ??
        null;

    const selectedVariable =
        selectedItem ? variablesById.get(selectedItem.variableId) ?? null : null;


    const placedVariableIds = useMemo(
        () => new Set(items.map((item) => item.variableId)),
        [items],
    );

    const visiblePlacedVariableIds = useMemo(() => {
        const ids = new Set(placedVariableIds);

        if (pendingVariableDrag) {
            const pendingItem = items.find((item) => item.id === pendingVariableDrag.id);

            if (pendingItem) {
                ids.delete(pendingItem.variableId);
            }
        }

        return ids;
    }, [items, placedVariableIds, pendingVariableDrag]);

    const availableGroups = useMemo<string[]>(
        () =>
            Array.from(
                new Set(
                    synoptic.variables
                        .filter((variable) => !visiblePlacedVariableIds.has(variable.id))
                        .map((variable) => variable.group),
                ),
            ),
        [synoptic.variables, visiblePlacedVariableIds],
    );

    useEffect(() => {
        if (activeGroup !== "Todas" && !availableGroups.includes(activeGroup)) {
            setActiveGroup("Todas");
        }
    }, [activeGroup, availableGroups]);

    function getPointInCanvas(event: PointerEvent) {
        const rect = canvasRef.current?.getBoundingClientRect();

        if (!rect) {
            return null;
        }

        const x = ((event.clientX - rect.left) / rect.width) * 100;
        const y = ((event.clientY - rect.top) / rect.height) * 100;

        if (x < 0 || x > 100 || y < 0 || y > 100) {
            return null;
        }

        return { x, y };
    }

    function handleCardPointerDown(event: PointerEvent<HTMLDivElement>, item: MapItem) {
        const point = getPointInCanvas(event);

        if (!point) {
            return;
        }

        event.preventDefault();
        event.currentTarget.setPointerCapture(event.pointerId);

        setSelectedItemId(item.id);

        setDragState({
            id: item.id,
            pointerId: event.pointerId,
            offsetX: point.x - item.x,
            offsetY: point.y - item.y,
        });
    }

    function handleCardPointerMove(event: PointerEvent<HTMLDivElement>) {
        if (!dragState || event.pointerId !== dragState.pointerId) {
            return;
        }

        const point = getPointInCanvas(event);

        if (!point) {
            return;
        }

        setItems((currentItems) =>
            currentItems.map((item) =>
                item.id === dragState.id
                    ? {
                        ...item,
                        x: clampPercent(point.x - dragState.offsetX),
                        y: clampPercent(point.y - dragState.offsetY),
                    }
                    : item,
            ),
        );
    }

    function handleCardPointerUp(event: PointerEvent<HTMLDivElement>) {
        if (dragState && event.pointerId === dragState.pointerId) {
            event.currentTarget.releasePointerCapture(event.pointerId);
            setDragState(null);
        }
    }

    function createMapItemFromVariable(variable: SynopticVariable, point: { x: number; y: number }) {
        const newItem: MapItem = {
            id: `map-item-${crypto.randomUUID()}`,
            variableId: variable.id,
            x: clampPercent(point.x),
            y: clampPercent(point.y),
            variant: "compact",
            showLabel: true,
        };

        setItems((currentItems) => [...currentItems, newItem]);
        setSelectedItemId(newItem.id);

        return newItem;
    }

    function handleVariablePointerDown(
        event: PointerEvent<HTMLDivElement>,
        variable: SynopticVariable,
    ) {
        event.preventDefault();
        event.currentTarget.setPointerCapture(event.pointerId);

        const point = getPointInCanvas(event) ?? {
            x: 50,
            y: 50,
        };

        const newItem = createMapItemFromVariable(variable, point);

        setPendingVariableDrag({
            id: newItem.id,
            pointerId: event.pointerId,
        });

        setDragState({
            id: newItem.id,
            pointerId: event.pointerId,
            offsetX: 0,
            offsetY: 0,
        });
    }

    function handleVariablePointerMove(event: PointerEvent<HTMLDivElement>) {
        if (!pendingVariableDrag || event.pointerId !== pendingVariableDrag.pointerId) {
            return;
        }

        const point = getPointInCanvas(event);

        if (!point) {
            return;
        }

        setItems((currentItems) =>
            currentItems.map((item) =>
                item.id === pendingVariableDrag.id
                    ? {
                        ...item,
                        x: clampPercent(point.x),
                        y: clampPercent(point.y),
                    }
                    : item,
            ),
        );
    }

    function handleVariablePointerUp(event: PointerEvent<HTMLDivElement>) {
        if (!pendingVariableDrag || event.pointerId !== pendingVariableDrag.pointerId) {
            return;
        }

        const point = getPointInCanvas(event);

        if (!point) {
            setItems((currentItems) =>
                currentItems.filter((item) => item.id !== pendingVariableDrag.id),
            );

            if (selectedItemId === pendingVariableDrag.id) {
                setSelectedItemId(null);
            }
        }

        if (event.currentTarget.hasPointerCapture(event.pointerId)) {
            event.currentTarget.releasePointerCapture(event.pointerId);
        }

        setPendingVariableDrag(null);
        setDragState(null);
    }

    function handleRemoveSelectedItem() {
        if (!selectedItemId) {
            return;
        }

        setItems((currentItems) =>
            currentItems.filter((item) => item.id !== selectedItemId),
        );

        setSelectedItemId(null);
    }

    function handleSelectedVariantChange(variant: CardVariant) {
        if (!selectedItemId) {
            return;
        }

        setItems((currentItems) =>
            currentItems.map((item) =>
                item.id === selectedItemId
                    ? {
                        ...item,
                        variant,
                    }
                    : item,
            ),
        );
    }

    function handleSelectedShowLabelChange(showLabel: boolean) {
        if (!selectedItemId) {
            return;
        }

        setItems((currentItems) =>
            currentItems.map((item) =>
                item.id === selectedItemId
                    ? {
                        ...item,
                        showLabel,
                    }
                    : item,
            ),
        );
    }

    useEffect(() => {
        function handleKeyDown(event: KeyboardEvent) {
            if (
                event.key !== "Delete" &&
                event.key !== "Backspace"
            ) {
                return;
            }

            if (!selectedItemId) {
                return;
            }

            const activeElement = document.activeElement;

            const typing =
                activeElement instanceof HTMLInputElement ||
                activeElement instanceof HTMLTextAreaElement ||
                activeElement instanceof HTMLSelectElement;

            if (typing) {
                return;
            }

            setItems((currentItems) =>
                currentItems.filter(
                    (item) => item.id !== selectedItemId,
                ),
            );

            setSelectedItemId(null);
        }

        window.addEventListener("keydown", handleKeyDown);

        return () => {
            window.removeEventListener("keydown", handleKeyDown);
        };
    }, [selectedItemId]);

    return (
        <div className={isDark ? "h-full text-white" : "h-full text-[#0F172A]"}>
            <div className="flex h-[calc(100vh-104px)] min-h-0 min-w-0 flex-col gap-2 overflow-hidden min-[1220px]:gap-3">
                <WorkspaceBar isDark={isDark} />

                <main className="grid min-h-0 min-w-0 flex-1 grid-cols-[180px_minmax(0,1fr)_210px] gap-2 overflow-hidden min-[1180px]:grid-cols-[200px_minmax(0,1fr)_230px] min-[1320px]:grid-cols-[230px_minmax(0,1fr)_260px] min-[1450px]:grid-cols-[270px_minmax(0,1fr)_290px] min-[1220px]:gap-3">
                    <VariablesPanel
                        isDark={isDark}
                        variables={synoptic.variables}
                        placedVariableIds={visiblePlacedVariableIds}
                        availableGroups={availableGroups}
                        activeGroup={activeGroup}
                        search={search}
                        onActiveGroupChange={setActiveGroup}
                        onSearchChange={setSearch}
                        onVariablePointerDown={handleVariablePointerDown}
                        onVariablePointerMove={handleVariablePointerMove}
                        onVariablePointerUp={handleVariablePointerUp}
                    />

                    <section className={isDark ? "relative min-h-0 min-w-0 overflow-hidden rounded-[8px] bg-[#0E1726]" : "relative min-h-0 min-w-0 overflow-hidden rounded-[8px] border border-[#D7DEE8] bg-white"}>
                        <Toolbar isDark={isDark} />

                        <CanvasMock
                            isDark={isDark}
                            canvasRef={canvasRef}
                            items={items}
                            variablesById={variablesById}
                            selectedItemId={selectedItemId}
                            draggingItemId={dragState?.id}
                            onCardPointerDown={handleCardPointerDown}
                            onCardPointerMove={handleCardPointerMove}
                            onCardPointerUp={handleCardPointerUp}
                        />
                    </section>

                    <PropertiesPanel
                        isDark={isDark}
                        selectedItem={selectedItem}
                        selectedVariable={selectedVariable}
                        onRemoveSelectedItem={handleRemoveSelectedItem}
                        onVariantChange={handleSelectedVariantChange}
                        onShowLabelChange={handleSelectedShowLabelChange}
                    />
                </main>
            </div>
        </div>
    );
}

function WorkspaceBar({ isDark }: { isDark: boolean }) {
    return (
        <section className="flex h-[52px] shrink-0 items-center justify-between gap-3 bg-transparent min-[1220px]:h-[58px]">
            <div className="min-w-0">
                <p className="text-[11px] font-black uppercase leading-none tracking-[0.28em] text-[#18B8A6]">
                    Workspace sinótico
                </p>

                <div className="mt-2 flex items-center gap-2">
                    <button
                        type="button"
                        className={isDark ? "flex min-w-0 items-center gap-2 text-[15px] font-black leading-none tracking-[-0.03em] text-white" : "flex min-w-0 items-center gap-2 text-[15px] font-black leading-none tracking-[-0.03em] text-[#0F172A]"}
                    >
                        <span className="truncate">Estufa Principal</span>
                        <ChevronDown className="h-4 w-4 shrink-0 text-[#7F8CA3]" />
                    </button>
                </div>
            </div>

            <div className="flex min-w-0 items-center gap-2 overflow-x-auto pb-1">
                <WorkspaceButton isDark={isDark} icon={<FolderPlus className="h-4 w-4" />} label="Novo" />
                <WorkspaceButton isDark={isDark} icon={<Save className="h-4 w-4" />} label="Guardar" primary />
                <WorkspaceButton isDark={isDark} icon={<RefreshCw className="h-4 w-4" />} label="Atualizar" />

                <div className={isDark ? "ml-1 flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#A8B3C7] min-[1220px]:ml-3 min-[1220px]:px-4" : "ml-1 flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#D7DEE8] bg-white px-3 text-xs font-black text-slate-600 min-[1220px]:ml-3 min-[1220px]:px-4"}>
                    <span className="h-2 w-2 rounded-full bg-[#18B8A6]" />
                    Alterações guardadas
                </div>
            </div>
        </section>
    );
}

function WorkspaceButton({
    isDark,
    icon,
    label,
    primary,
}: {
    isDark: boolean;
    icon: ReactNode;
    label: string;
    primary?: boolean;
}) {
    if (primary) {
        return (
            <button
                type="button"
                className="flex h-9 shrink-0 items-center gap-2 rounded-[6px] bg-[#18B8A6] px-3 text-xs font-black text-white transition hover:bg-[#21C7B5]"
            >
                {icon}
                {label}
            </button>
        );
    }

    return (
        <button
            type="button"
            className={
                isDark
                    ? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#0E1726] px-3 text-xs font-black text-[#D7DEE8] transition hover:border-[#36506D] hover:text-white"
                    : "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#D7DEE8] bg-white px-3 text-xs font-black text-slate-700 transition hover:bg-[#F8FAFC] hover:text-[#0F172A]"
            }
        >
            {icon}
            {label}
        </button>
    );
}

function VariablesPanel({
    isDark,
    variables,
    placedVariableIds,
    availableGroups,
    activeGroup,
    search,
    onActiveGroupChange,
    onSearchChange,
    onVariablePointerDown,
    onVariablePointerMove,
    onVariablePointerUp,
}: {
    isDark: boolean;
    variables: SynopticVariable[];
    placedVariableIds: Set<string>;
    availableGroups: string[];
    activeGroup: string;
    search: string;
    onActiveGroupChange: (group: string) => void;
    onSearchChange: (value: string) => void;
    onVariablePointerDown: (
        event: PointerEvent<HTMLDivElement>,
        variable: SynopticVariable,
    ) => void;
    onVariablePointerMove: (event: PointerEvent<HTMLDivElement>) => void;
    onVariablePointerUp: (event: PointerEvent<HTMLDivElement>) => void;
}) {
    const groups = availableGroups;
    const tabs = ["Todas", ...availableGroups];

    const filteredVariables = variables.filter((variable) => {
        if (placedVariableIds.has(variable.id)) {
            return false;
        }

        const matchesGroup =
            activeGroup === "Todas" ||
            variable.group === activeGroup;

        const query = search.trim().toLowerCase();

        const matchesSearch =
            query.length === 0 ||
            `${variable.label} ${variable.key} ${variable.unit}`
                .toLowerCase()
                .includes(query);

        return matchesGroup && matchesSearch;
    });

    return (
        <aside
            className={
                isDark
                    ? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
                    : "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
            }
        >
            <div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
                <div>
                    <h2 className="text-base font-black">Variáveis</h2>
                    <p className="text-[11px] font-bold text-[#7F8CA3]">
                        Arraste para a imagem
                    </p>
                </div>

                <X className="h-4 w-4 text-[#7F8CA3]" />
            </div>

            <div className="space-y-3 p-3">
                <div className="flex items-center gap-3 overflow-x-auto text-xs font-bold min-[1450px]:gap-4">
                    {tabs.map((item) => (
                        <button
                            key={item}
                            type="button"
                            onClick={() => onActiveGroupChange(item)}
                            className={
                                activeGroup === item
                                    ? "shrink-0 border-b-2 border-[#18B8A6] pb-2 text-[#18B8A6]"
                                    : isDark
                                        ? "shrink-0 pb-2 text-[#7F8CA3] transition hover:text-white"
                                        : "shrink-0 pb-2 text-slate-500 transition hover:text-[#0F172A]"
                            }
                        >
                            {item}
                        </button>
                    ))}
                </div>

                <div>
                    <label
                        className={
                            isDark
                                ? "flex h-9 min-w-0 items-center gap-2 rounded-[6px] border border-[#263247] bg-[#07101B] px-3 text-xs text-[#7F8CA3]"
                                : "flex h-9 min-w-0 items-center gap-2 rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] px-3 text-xs text-slate-500"
                        }
                    >
                        <Search className="h-4 w-4 shrink-0" />
                        <input
                            value={search}
                            onChange={(event) => onSearchChange(event.target.value)}
                            placeholder="Procurar variável..."
                            className="min-w-0 flex-1 bg-transparent font-bold text-inherit outline-none placeholder:text-[#7F8CA3]"
                        />
                    </label>
                </div>
            </div>

            <div className="min-h-0 flex-1 space-y-3 overflow-y-auto px-3 pb-3">
                {groups.map((group) => {
                    const groupVariables = filteredVariables.filter(
                        (variable) => variable.group === group,
                    );

                    if (activeGroup !== "Todas" && activeGroup !== group) {
                        return null;
                    }

                    return (
                        <div
                            key={group}
                            className={
                                isDark
                                    ? "overflow-hidden rounded-[7px] border border-[#1C2A3D] bg-[#111A2B]"
                                    : "overflow-hidden rounded-[7px] border border-[#E2E8F0] bg-[#F8FAFC]"
                            }
                        >
                            <div
                                className={
                                    isDark
                                        ? "flex h-8 items-center justify-between bg-white/[0.03] px-3 text-sm font-black"
                                        : "flex h-8 items-center justify-between bg-white px-3 text-sm font-black"
                                }
                            >
                                <span>{group}</span>

                                <div className="flex items-center gap-2">
                                    <span className="text-[10px] font-black text-[#7F8CA3]">
                                        {groupVariables.length}
                                    </span>
                                    <ChevronDown className="h-4 w-4 text-[#7F8CA3]" />
                                </div>
                            </div>

                            {groupVariables.length === 0 ? (
                                <div className={isDark ? "border-t border-[#1C2A3D] px-3 py-3 text-[11px] font-bold text-[#7F8CA3]" : "border-t border-[#E2E8F0] px-3 py-3 text-[11px] font-bold text-slate-500"}>
                                    Sem variáveis disponíveis
                                </div>
                            ) : (
                                groupVariables.map((variable) => {
                                    const Icon = variable.icon;

                                    return (
                                        <div
                                            key={variable.id}
                                            onPointerDown={(event) => onVariablePointerDown(event, variable)}
                                            onPointerMove={onVariablePointerMove}
                                            onPointerUp={onVariablePointerUp}
                                            onPointerCancel={onVariablePointerUp}
                                            className={
                                                isDark
                                                    ? "flex h-9 cursor-grab items-center gap-2 border-t border-[#1C2A3D] px-3 text-[11px] transition hover:bg-white/[0.04] active:cursor-grabbing"
                                                    : "flex h-9 cursor-grab items-center gap-2 border-t border-[#E2E8F0] px-3 text-[11px] transition hover:bg-white active:cursor-grabbing"
                                            }
                                        >
                                            <span
                                                className="shrink-0"
                                                style={{ color: variable.color }}
                                            >
                                                <Icon className="h-4 w-4" />
                                            </span>

                                            <span className="min-w-0 flex-1 truncate font-bold">
                                                {variable.label}
                                            </span>

                                            <span className="shrink-0 font-black">
                                                {formatVariableValue(variable)}
                                            </span>

                                            <span
                                                className={
                                                    variable.connected
                                                        ? "h-2 w-2 shrink-0 rounded-full bg-[#22C55E]"
                                                        : "h-2 w-2 shrink-0 rounded-full bg-[#7F8CA3]"
                                                }
                                            />
                                        </div>
                                    );
                                })
                            )}
                        </div>
                    );
                })}
            </div>

            <div
                className={
                    isDark
                        ? "m-3 rounded-[7px] border border-[#263247] bg-[#111A2B] p-3 text-center"
                        : "m-3 rounded-[7px] border border-[#D7DEE8] bg-[#F8FAFC] p-3 text-center"
                }
            >
                <p className="text-xs font-black">Drag & drop</p>
                <p className="mt-1 text-[11px] text-[#7F8CA3]">
                    Arraste uma variável real para criar um cartão no mapa.
                </p>
            </div>
        </aside>
    );
}

function Toolbar({ isDark }: { isDark: boolean }) {
    const tools = [
        { label: "Selecionar", icon: <LocateFixed className="h-4 w-4" />, active: true },
        { label: "Mover", icon: <Move className="h-4 w-4" /> },
        { label: "Texto", icon: <span className="text-sm font-black">T</span> },
    ];

    return (
        <div className="absolute left-3 right-3 top-3 z-20 flex items-start justify-between gap-2 min-[1450px]:left-4 min-[1450px]:right-4 min-[1450px]:top-4">
            <div className={isDark ? "flex max-w-[calc(100%-88px)] items-center gap-1 overflow-x-auto rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur" : "flex max-w-[calc(100%-88px)] items-center gap-1 overflow-x-auto rounded-[8px] border border-[#D7DEE8] bg-white/92 p-1 shadow-xl backdrop-blur"}>
                {tools.map((tool) => (
                    <button
                        key={tool.label}
                        className={
                            tool.active
                                ? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/15 px-3 text-xs font-black text-[#18B8A6] min-[1450px]:px-4"
                                : isDark
                                    ? "flex h-9 shrink-0 items-center gap-2 rounded-[6px] px-3 text-xs font-bold text-[#A8B3C7] transition hover:bg-white/10 hover:text-white min-[1450px]:px-4"
                                    : "flex h-9 shrink-0 items-center gap-2 rounded-[6px] px-3 text-xs font-bold text-slate-600 transition hover:bg-[#F1F5F9] hover:text-[#0F172A] min-[1450px]:px-4"
                        }
                    >
                        {tool.icon}
                        <span className="hidden min-[1120px]:inline">{tool.label}</span>
                    </button>
                ))}
            </div>

            <div className={isDark ? "flex shrink-0 items-center gap-1 rounded-[8px] border border-[#263247] bg-[#07101B]/92 p-1 shadow-xl backdrop-blur" : "flex shrink-0 items-center gap-1 rounded-[8px] border border-[#D7DEE8] bg-white/92 p-1 shadow-xl backdrop-blur"}>
                <button className={smallToolClass(isDark)}>
                    <Settings2 className="h-4 w-4" />
                </button>
            </div>
        </div>
    );
}

function CanvasMock({
    isDark,
    canvasRef,
    items,
    variablesById,
    selectedItemId,
    draggingItemId,
    onCardPointerDown,
    onCardPointerMove,
    onCardPointerUp,
}: {
    isDark: boolean;
    canvasRef: RefObject<HTMLDivElement | null>;
    items: MapItem[];
    variablesById: Map<string, SynopticVariable>;
    selectedItemId: string | null;
    draggingItemId?: string;
    onCardPointerDown: (event: PointerEvent<HTMLDivElement>, item: MapItem) => void;
    onCardPointerMove: (event: PointerEvent<HTMLDivElement>) => void;
    onCardPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
}) {
    return (
        <div className={isDark ? "flex h-full w-full items-center justify-center overflow-hidden bg-[#07101B] p-2" : "flex h-full w-full items-center justify-center overflow-hidden bg-[#F8FAFC] p-2"}>
            <div
                ref={canvasRef}
                className="relative h-full max-h-full max-w-full overflow-hidden rounded-[6px]"
                style={{ aspectRatio: "16 / 9" }}
            >
                <img
                    src={satelliteImage}
                    alt="Vista aérea da instalação"
                    className="absolute inset-0 h-full w-full select-none object-fill"
                    draggable={false}
                />

                {items.length === 0 && (
                    <div className={isDark ? "pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2 rounded-[8px] border border-dashed border-[#18B8A6]/50 bg-[#07101B]/80 px-5 py-4 text-center shadow-xl" : "pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2 rounded-[8px] border border-dashed border-[#18B8A6]/60 bg-white/85 px-5 py-4 text-center shadow-xl"}>
                        <p className={isDark ? "text-sm font-black text-white" : "text-sm font-black text-[#0F172A]"}>
                            Arraste variáveis para a imagem
                        </p>
                        <p className="mt-1 text-xs font-bold text-[#7F8CA3]">
                            Os cartões ficam presos ao ponto exato da imagem.
                        </p>
                    </div>
                )}

                {items.map((item) => {
                    const variable = variablesById.get(item.variableId);

                    if (!variable) {
                        return null;
                    }

                    return (
                        <MapCard
                            key={item.id}
                            item={item}
                            variable={variable}
                            selected={item.id === selectedItemId}
                            dragging={item.id === draggingItemId}
                            onPointerDown={onCardPointerDown}
                            onPointerMove={onCardPointerMove}
                            onPointerUp={onCardPointerUp}
                        />
                    );
                })}

                <div className={isDark ? "absolute bottom-4 left-4 z-20 flex flex-col overflow-hidden rounded-[7px] border border-[#263247] bg-[#07101B]/90 shadow-xl" : "absolute bottom-4 left-4 z-20 flex flex-col overflow-hidden rounded-[7px] border border-[#D7DEE8] bg-white/90 shadow-xl"}>
                    <button className="grid h-9 w-9 place-items-center text-white hover:bg-white/10 min-[1450px]:h-10 min-[1450px]:w-10">
                        <Plus className="h-5 w-5" />
                    </button>
                    <button className="grid h-9 w-9 place-items-center border-t border-[#263247] text-white hover:bg-white/10 min-[1450px]:h-10 min-[1450px]:w-10">
                        <ZoomOut className="h-5 w-5" />
                    </button>
                    <button className="grid h-9 w-9 place-items-center border-t border-[#263247] text-white hover:bg-white/10 min-[1450px]:h-10 min-[1450px]:w-10">
                        <ZoomIn className="h-5 w-5" />
                    </button>
                </div>

                <div className={isDark ? "absolute bottom-4 right-4 z-20 rounded-[7px] bg-[#07101B]/90 px-3 py-2 text-xs font-black text-white shadow-xl" : "absolute bottom-4 right-4 z-20 rounded-[7px] bg-white/90 px-3 py-2 text-xs font-black text-[#0F172A] shadow-xl"}>
                    100%
                </div>
            </div>
        </div>
    );
}

function MapCard({
    item,
    variable,
    selected,
    dragging,
    onPointerDown,
    onPointerMove,
    onPointerUp,
}: {
    item: MapItem;
    variable: SynopticVariable;
    selected: boolean;
    dragging: boolean;
    onPointerDown: (event: PointerEvent<HTMLDivElement>, item: MapItem) => void;
    onPointerMove: (event: PointerEvent<HTMLDivElement>) => void;
    onPointerUp: (event: PointerEvent<HTMLDivElement>) => void;
}) {
    const Icon = variable.icon;
    const isLarge = item.variant === "large";

    return (
        <div
            role="button"
            tabIndex={0}
            aria-label={`Mover ${variable.label}`}
            onPointerDown={(event) => onPointerDown(event, item)}
            onPointerMove={onPointerMove}
            onPointerUp={onPointerUp}
            onPointerCancel={onPointerUp}
            className="absolute z-10 cursor-grab touch-none select-none active:cursor-grabbing"
            style={{
                left: `${item.x}%`,
                top: `${item.y}%`,
                transform: "translate(-50%, -100%)",
                boxShadow: dragging ? "0 24px 80px rgba(24,184,166,0.26)" : undefined,
            }}
        >
            <div
                className={
                    selected
                        ? `relative mb-7 rounded-[8px] border border-[#4FD1C5] bg-[#07101B]/92 shadow-2xl ${isLarge ? "w-[210px] px-4 py-3" : "w-[150px] px-3 py-2"
                        }`
                        : `relative mb-7 rounded-[8px] border border-[#34425B] bg-[#07101B]/90 shadow-2xl ${isLarge ? "w-[210px] px-4 py-3" : "w-[150px] px-3 py-2"
                        }`
                }
            >
                {selected && (
                    <>
                        {[
                            "-top-1 -left-1",
                            "-top-1 -right-1",
                            "-bottom-1 -left-1",
                            "-bottom-1 -right-1",
                        ].map((position) => (
                            <span
                                key={position}
                                className={`absolute h-2 w-2 rounded-full bg-white ${position}`}
                            />
                        ))}
                    </>
                )}

                <div className={isLarge ? "pointer-events-none space-y-3" : "pointer-events-none flex items-center gap-2"}>
                    <div className={isLarge ? "flex items-center gap-2" : "contents"}>
                        <span className="shrink-0" style={{ color: variable.color }}>
                            <Icon className={isLarge ? "h-8 w-8" : "h-7 w-7"} />
                        </span>

                        <div className="min-w-0">
                            {item.showLabel && (
                                <p className={isLarge ? "truncate text-xs font-bold text-[#A8B3C7]" : "truncate text-[10px] font-bold text-[#A8B3C7]"}>
                                    {variable.label}
                                </p>
                            )}

                            <p className={isLarge ? "mt-1 text-2xl font-black leading-none text-white" : "mt-0.5 text-lg font-black leading-none text-white"}>
                                {formatVariableValue(variable)}
                            </p>
                        </div>
                    </div>

                    {isLarge && (
                        <div className="grid grid-cols-2 gap-2 border-t border-white/10 pt-2 text-[10px] font-bold text-[#7F8CA3]">
                            <span>{variable.group}</span>
                            <span className="text-right">
                                {variable.connected ? "Online" : "Offline"}
                            </span>
                        </div>
                    )}
                </div>
            </div>

            <span
                className="pointer-events-none absolute left-1/2 top-[calc(100%-28px)] h-7 w-px -translate-x-1/2 bg-white/70"
                aria-hidden
            />

            <span
                className="pointer-events-none absolute left-1/2 top-full h-2.5 w-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full border border-white bg-[#18B8A6]"
                aria-hidden
            />
        </div>
    );
}

function PropertiesPanel({
    isDark,
    selectedItem,
    selectedVariable,
    onRemoveSelectedItem,
    onVariantChange,
    onShowLabelChange,
}: {
    isDark: boolean;
    selectedItem: MapItem | null;
    selectedVariable: SynopticVariable | null;
    onRemoveSelectedItem: () => void;
    onVariantChange: (variant: CardVariant) => void;
    onShowLabelChange: (showLabel: boolean) => void;
}) {
    if (!selectedItem || !selectedVariable) {
        return (
            <aside
                className={
                    isDark
                        ? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
                        : "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
                }
            >
                <div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
                    <h2 className="text-base font-black">Propriedades</h2>
                    <X className="h-4 w-4 text-[#7F8CA3]" />
                </div>

                <div className="min-h-0 flex-1 overflow-y-auto p-3 min-[1450px]:p-4">
                    <div className={isDark ? "rounded-[7px] border border-[#263247] bg-[#07101B] p-4 text-center" : "rounded-[7px] border border-[#D7DEE8] bg-[#F8FAFC] p-4 text-center"}>
                        <p className="text-sm font-black">Nenhum item selecionado</p>
                        <p className="mt-1 text-xs font-bold text-[#7F8CA3]">
                            Arraste uma variável para a imagem.
                        </p>
                    </div>
                </div>
            </aside>
        );
    }

    const Icon = selectedVariable.icon;

    return (
        <aside
            className={
                isDark
                    ? "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#263247] bg-[#0E1726]"
                    : "flex min-h-0 min-w-0 flex-col rounded-[8px] border border-[#D7DEE8] bg-white"
            }
        >
            <div className={isDark ? "flex h-12 shrink-0 items-center justify-between border-b border-[#263247]/70 px-3 min-[1450px]:px-4" : "flex h-12 shrink-0 items-center justify-between border-b border-[#D7DEE8] px-3 min-[1450px]:px-4"}>
                <h2 className="text-base font-black">Propriedades</h2>
                <X className="h-4 w-4 text-[#7F8CA3]" />
            </div>

            <div className="min-h-0 flex-1 overflow-y-auto p-3 min-[1450px]:p-4">
                <div className="mb-5 flex items-center gap-3">
                    <div
                        className="grid h-10 w-10 place-items-center rounded-[6px] bg-[#0EA5E9]/15"
                        style={{ color: selectedVariable.color }}
                    >
                        <Icon className="h-5 w-5" />
                    </div>

                    <div className="min-w-0">
                        <p className="text-xs font-bold text-[#7F8CA3]">Item selecionado</p>
                        <p className="truncate text-sm font-black">{selectedVariable.label}</p>
                    </div>
                </div>

                <PanelSection title="Posição">
                    <div className="grid grid-cols-2 gap-2">
                        <InputMock label="X" value={`${selectedItem.x.toFixed(1)} %`} isDark={isDark} />
                        <InputMock label="Y" value={`${selectedItem.y.toFixed(1)} %`} isDark={isDark} />
                    </div>
                </PanelSection>

                <PanelSection title="Dados">
                    <InputMock label="Grupo" value={selectedVariable.group} isDark={isDark} />
                    <InputMock label="Valor" value={formatVariableValue(selectedVariable)} isDark={isDark} />
                </PanelSection>

                <PanelSection title="Cartão">
                    <SegmentedControl
                        isDark={isDark}
                        value={selectedItem.variant}
                        options={[
                            { label: "Compacto", value: "compact" },
                            { label: "Grande", value: "large" },
                        ]}
                        onChange={(value) => onVariantChange(value as CardVariant)}
                    />

                    <button
                        type="button"
                        onClick={() => onShowLabelChange(!selectedItem.showLabel)}
                        className={
                            selectedItem.showLabel
                                ? "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#18B8A6] bg-[#18B8A6]/10 px-3 text-sm font-black text-[#18B8A6]"
                                : isDark
                                    ? "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#263247] bg-[#07101B] px-3 text-sm font-bold text-[#A8B3C7]"
                                    : "flex h-10 w-full items-center justify-between rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] px-3 text-sm font-bold text-slate-600"
                        }
                    >
                        Mostrar nome
                        <span>{selectedItem.showLabel ? "Ligado" : "Desligado"}</span>
                    </button>
                </PanelSection>

                <button
                    type="button"
                    onClick={onRemoveSelectedItem}
                    className="mt-4 flex h-11 w-full items-center justify-center gap-2 rounded-[6px] border border-red-500/70 text-sm font-black text-red-400 transition hover:bg-red-500 hover:text-white"
                >
                    Remover do mapa
                </button>
            </div>
        </aside>
    );
}

function PanelSection({
    title,
    children,
}: {
    title: string;
    children: ReactNode;
}) {
    return (
        <section className="mb-6 space-y-3">
            <h3 className="text-sm font-black">{title}</h3>
            {children}
        </section>
    );
}

function InputMock({
    label,
    value,
    isDark,
}: {
    label: string;
    value: string;
    isDark: boolean;
}) {
    return (
        <div
            className={
                isDark
                    ? "flex h-10 items-center justify-between rounded-[6px] border border-[#263247] bg-[#07101B] px-3"
                    : "flex h-10 items-center justify-between rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] px-3"
            }
        >
            <span className="text-xs font-bold text-[#7F8CA3]">{label}</span>
            <span className="text-sm font-black">{value}</span>
        </div>
    );
}

function clampPercent(value: number) {
    return Math.min(96, Math.max(4, value));
}

function SegmentedControl({
    isDark,
    value,
    options,
    onChange,
}: {
    isDark: boolean;
    value: string;
    options: { label: string; value: string }[];
    onChange: (value: string) => void;
}) {
    return (
        <div className={isDark ? "grid grid-cols-2 rounded-[6px] border border-[#263247] bg-[#07101B] p-1" : "grid grid-cols-2 rounded-[6px] border border-[#D7DEE8] bg-[#F8FAFC] p-1"}>
            {options.map((option) => (
                <button
                    key={option.value}
                    type="button"
                    onClick={() => onChange(option.value)}
                    className={
                        value === option.value
                            ? "h-8 rounded-[5px] bg-[#18B8A6] text-xs font-black text-white"
                            : isDark
                                ? "h-8 rounded-[5px] text-xs font-bold text-[#7F8CA3] transition hover:text-white"
                                : "h-8 rounded-[5px] text-xs font-bold text-slate-500 transition hover:text-[#0F172A]"
                    }
                >
                    {option.label}
                </button>
            ))}
        </div>
    );
}

function smallToolClass(isDark: boolean) {
    return isDark
        ? "grid h-9 w-9 place-items-center rounded-[6px] text-[#A8B3C7] transition hover:bg-white/10 hover:text-white"
        : "grid h-9 w-9 place-items-center rounded-[6px] text-slate-600 transition hover:bg-[#F1F5F9] hover:text-[#0F172A]";
}

function formatVariableValue(variable: SynopticVariable) {
    if (variable.value === null || variable.value === undefined) {
        return "—";
    }

    if (typeof variable.value === "number") {
        const value = Number.isInteger(variable.value)
            ? variable.value.toString()
            : variable.value.toFixed(1);

        return `${value} ${variable.unit}`.trim();
    }

    return `${variable.value} ${variable.unit}`.trim();
}
export default SynopticPage;