import maplibregl from "maplibre-gl";
import { Geometry } from "@/uhm/lib/editor/state/useEditorState";
import type { ModeGetter } from "@/uhm/lib/map/engines/engineTypes";
import { snapToNearestGeometry } from "@/uhm/lib/map/engines/snapUtils";

// Khởi tạo engine vẽ polygon tự do theo chuỗi click.
export function initDrawing(
    map: maplibregl.Map,
    getMode: ModeGetter,
    onComplete: (geometry: Geometry) => void
) {
    let coords: [number, number][] = [];

    const clearPreview = () => {
        (map.getSource("draw-preview") as maplibregl.GeoJSONSource | undefined)?.setData({
            type: "FeatureCollection",
            features: [],
        });
    };

    const cancelDrawing = () => {
        coords = [];
        clearPreview();
    };

    // Đóng vòng polygon nếu điểm cuối chưa trùng điểm đầu.
    function closePolygon(c: [number, number][]) {
        if (c.length < 3) return c;
        const first = c[0];
        const last = c[c.length - 1];

        if (first[0] !== last[0] || first[1] !== last[1]) {
            return [...c, first];
        }
        return c;
    }

    // Cập nhật layer preview trong lúc đang vẽ.
    function update(c: [number, number][]) {
        const closed = closePolygon(c);

        (map.getSource("draw-preview") as maplibregl.GeoJSONSource)?.setData({
            type: "FeatureCollection",
            features: [
                {
                    type: "Feature",
                    properties: {},
                    geometry: {
                        type: "Polygon",
                        coordinates: [closed],
                    },
                },
            ],
        });
    }

    // Ghi nhận đỉnh polygon mới khi click map.
    function onClick(e: maplibregl.MapLayerMouseEvent) {
        if (getMode() !== "draw") return;

        let lngLat = e.lngLat;
        // Dùng Shift (hoặc Alt nếu Shift bị maplibre chiếm dụng) để snap
        if (e.originalEvent.shiftKey || e.originalEvent.altKey) {
            lngLat = snapToNearestGeometry(map, e.lngLat, e.point);
        }

        coords.push([lngLat.lng, lngLat.lat] as [number, number]);
        update(coords);
    }

    // Render preview polygon với điểm chuột hiện tại.
    function onMove(e: maplibregl.MapLayerMouseEvent) {
        if (getMode() !== "draw" || coords.length === 0) return;

        let lngLat = e.lngLat;
        if (e.originalEvent.shiftKey || e.originalEvent.altKey) {
            lngLat = snapToNearestGeometry(map, e.lngLat, e.point);
        }

        const preview: [number, number][] = [
            ...coords,
            [lngLat.lng, lngLat.lat] as [number, number],
        ];
        update(preview);
    }

    // Hoàn tất polygon, trả geometry ra ngoài và reset preview.
    function finishDrawing() {
        if (getMode() !== "draw" || coords.length < 3) return;

        const geometry: Geometry = {
            type: "Polygon",
            coordinates: [closePolygon(coords)],
        };

        onComplete(geometry);
        cancelDrawing();
    }

    // Lắng nghe Enter để chốt polygon.
    function onKeyDown(e: KeyboardEvent) {
        if (getMode() !== "draw") return;
        if (e.key === "Enter") {
            e.preventDefault();
            finishDrawing();
            return;
        }
        if (e.key === "Escape") {
            e.preventDefault();
            cancelDrawing();
            return;
        }
        if (e.key === "Backspace") {
            e.preventDefault();
            coords = coords.slice(0, -1);
            if (coords.length) {
                update(coords);
            } else {
                clearPreview();
            }
        }
    }

    // Tắt tính năng box zoom và double click zoom để Shift không bị lỗi
    map.boxZoom.disable();
    map.doubleClickZoom.disable();

    map.on("click", onClick);
    map.on("mousemove", onMove);
    document.addEventListener("keydown", onKeyDown);

    const cleanup = () => {
        map.boxZoom.enable();
        map.doubleClickZoom.enable();
        map.off("click", onClick);
        map.off("mousemove", onMove);
        document.removeEventListener("keydown", onKeyDown);
        cancelDrawing();
    };

    return {
        cleanup,
        cancel: cancelDrawing,
    };
}
