function setStatus(element, message, type) {
    element.textContent = message;
    element.classList.remove('error', 'success');
    if (type) {
        element.classList.add(type);
    }
}

function roadColorByStatus(status) {
    if (status === 'nasional') {
        return '#dc2626';
    }
    if (status === 'provinsi') {
        return '#2563eb';
    }
    return '#16a34a';
}

function parcelColorByStatus(status) {
    if (status === 'SHM') {
        return '#ea580c';
    }
    if (status === 'HGB') {
        return '#0ea5e9';
    }
    if (status === 'HGU') {
        return '#22c55e';
    }
    return '#a855f7';
}

function calculatePolylineLengthMeters(latlngs) {
    let total = 0;
    for (let index = 1; index < latlngs.length; index += 1) {
        total += latlngs[index - 1].distanceTo(latlngs[index]);
    }
    return total;
}

function calculatePolygonAreaMeters(latlngs) {
    if (window.L && L.GeometryUtil && typeof L.GeometryUtil.geodesicArea === 'function') {
        return L.GeometryUtil.geodesicArea(latlngs);
    }

    const earthRadius = 6378137;
    const toRad = (degree) => degree * Math.PI / 180;

    let area = 0;
    for (let i = 0; i < latlngs.length; i += 1) {
        const p1 = latlngs[i];
        const p2 = latlngs[(i + 1) % latlngs.length];
        area += toRad(p2.lng - p1.lng) * (2 + Math.sin(toRad(p1.lat)) + Math.sin(toRad(p2.lat)));
    }

    return Math.abs(area * earthRadius * earthRadius / 2);
}

function polylineToWkt(latlngs) {
    const coordinates = latlngs.map((point) => `${point.lng} ${point.lat}`).join(', ');
    return `LINESTRING(${coordinates})`;
}

function polygonToWkt(latlngs) {
    const ring = latlngs.map((point) => `${point.lng} ${point.lat}`);
    if (ring[0] !== ring[ring.length - 1]) {
        ring.push(ring[0]);
    }
    return `POLYGON((${ring.join(', ')}))`;
}

async function parseJsonResponse(response) {
    const text = await response.text();
    try {
        return JSON.parse(text);
    } catch (error) {
        throw new Error('Response server bukan JSON valid.');
    }
}

document.addEventListener('DOMContentLoaded', async () => {
    const map = L.map('map').setView([-0.0605, 109.3449], 13);

    L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 19,
        attribution: '&copy; OpenStreetMap contributors'
    }).addTo(map);

    if (typeof window.addKecamatanLayer === 'function') {
        window.addKecamatanLayer(map, { fitBounds: true }).catch((error) => {
            console.warn('Data kecamatan belum termuat:', error);
        });
    }

    const editableLayer = new L.FeatureGroup();
    map.addLayer(editableLayer);

    const modalBackdrop = document.getElementById('modal-backdrop');
    const modalTitle = document.getElementById('modal-title');
    const featureForm = document.getElementById('feature-form');
    const roadFields = document.getElementById('road-fields');
    const parcelFields = document.getElementById('parcel-fields');
    const formStatus = document.getElementById('form-status');
    const cancelButton = document.getElementById('btn-cancel');

    let pendingLayer = null;
    let pendingType = null;
    let pendingMode = 'create';

    function closeModal(shouldRemovePendingLayer) {
        modalBackdrop.classList.remove('open');
        modalBackdrop.setAttribute('aria-hidden', 'true');
        setStatus(formStatus, '', '');

        if (shouldRemovePendingLayer && pendingMode === 'create' && pendingLayer) {
            editableLayer.removeLayer(pendingLayer);
        }

        pendingLayer = null;
        pendingType = null;
        pendingMode = 'create';
        featureForm.reset();
    }

    function openRoadModal(layer, mode, initialData) {
        pendingLayer = layer;
        pendingType = 'road';
        pendingMode = mode;

        modalTitle.textContent = mode === 'create' ? 'Tambah Data Jalan' : 'Update Data Jalan';
        roadFields.hidden = false;
        parcelFields.hidden = true;

        const latlngs = layer.getLatLngs();
        const lengthMeters = calculatePolylineLengthMeters(latlngs);

        document.getElementById('nama_jalan').value = initialData && initialData.nama_jalan ? initialData.nama_jalan : '';
        document.getElementById('status_jalan').value = initialData && initialData.status ? initialData.status : 'nasional';
        document.getElementById('panjang_meter').value = lengthMeters.toFixed(2);

        modalBackdrop.classList.add('open');
        modalBackdrop.setAttribute('aria-hidden', 'false');
    }

    function openParcelModal(layer, mode, initialData) {
        pendingLayer = layer;
        pendingType = 'parcel';
        pendingMode = mode;

        modalTitle.textContent = mode === 'create' ? 'Tambah Data Parsil Tanah' : 'Update Data Parsil Tanah';
        roadFields.hidden = true;
        parcelFields.hidden = false;

        const latlngs = layer.getLatLngs()[0];
        const areaM2 = calculatePolygonAreaMeters(latlngs);

        document.getElementById('nama_pemilik').value = initialData && initialData.nama_pemilik ? initialData.nama_pemilik : '';
        document.getElementById('status_kepemilikan').value = initialData && initialData.status_kepemilikan ? initialData.status_kepemilikan : 'SHM';
        document.getElementById('luas_m2').value = areaM2.toFixed(2);

        modalBackdrop.classList.add('open');
        modalBackdrop.setAttribute('aria-hidden', 'false');
    }

    function attachRoadPopup(layer) {
        const props = layer.featureProps;
        layer.setStyle({
            color: roadColorByStatus(props.status),
            weight: 5
        });

        layer.bindPopup(`
            <b>Jalan:</b> ${props.nama_jalan}<br>
            <b>Status:</b> ${props.status}<br>
            <b>Panjang:</b> ${Number(props.panjang_meter).toFixed(2)} m
            <div class="popup-actions">
                <button type="button" data-action="edit">Edit</button>
                <button type="button" class="btn-danger" data-action="delete">Hapus</button>
            </div>
            <div class="status" data-role="popup-status"></div>
        `);

        layer.on('popupopen', (event) => {
            const popupElement = event.popup.getElement();
            const editButton = popupElement.querySelector('[data-action="edit"]');
            const deleteButton = popupElement.querySelector('[data-action="delete"]');
            const popupStatus = popupElement.querySelector('[data-role="popup-status"]');

            editButton.addEventListener('click', () => {
                map.closePopup();
                openRoadModal(layer, 'update', layer.featureProps);
            });

            deleteButton.addEventListener('click', async () => {
                if (!window.confirm('Hapus data jalan ini?')) {
                    return;
                }

                setStatus(popupStatus, 'Menghapus data...', '');
                deleteButton.disabled = true;

                try {
                    const response = await fetch('api/road_delete.php', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json'
                        },
                        body: JSON.stringify({ id: layer.featureId })
                    });

                    const result = await parseJsonResponse(response);
                    if (!response.ok || !result.success) {
                        throw new Error(result.message || 'Gagal menghapus data jalan.');
                    }

                    editableLayer.removeLayer(layer);
                    map.closePopup();
                } catch (error) {
                    setStatus(popupStatus, error.message || 'Gagal menghapus data.', 'error');
                    deleteButton.disabled = false;
                }
            });
        });
    }

    function attachParcelPopup(layer) {
        const props = layer.featureProps;
        layer.setStyle({
            color: parcelColorByStatus(props.status_kepemilikan),
            fillColor: parcelColorByStatus(props.status_kepemilikan),
            fillOpacity: 0.35,
            weight: 3
        });

        layer.bindPopup(`
            <b>Pemilik:</b> ${props.nama_pemilik}<br>
            <b>Status:</b> ${props.status_kepemilikan}<br>
            <b>Luas:</b> ${Number(props.luas_m2).toFixed(2)} m²
            <div class="popup-actions">
                <button type="button" data-action="edit">Edit</button>
                <button type="button" class="btn-danger" data-action="delete">Hapus</button>
            </div>
            <div class="status" data-role="popup-status"></div>
        `);

        layer.on('popupopen', (event) => {
            const popupElement = event.popup.getElement();
            const editButton = popupElement.querySelector('[data-action="edit"]');
            const deleteButton = popupElement.querySelector('[data-action="delete"]');
            const popupStatus = popupElement.querySelector('[data-role="popup-status"]');

            editButton.addEventListener('click', () => {
                map.closePopup();
                openParcelModal(layer, 'update', layer.featureProps);
            });

            deleteButton.addEventListener('click', async () => {
                if (!window.confirm('Hapus data parsil ini?')) {
                    return;
                }

                setStatus(popupStatus, 'Menghapus data...', '');
                deleteButton.disabled = true;

                try {
                    const response = await fetch('api/parcel_delete.php', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json'
                        },
                        body: JSON.stringify({ id: layer.featureId })
                    });

                    const result = await parseJsonResponse(response);
                    if (!response.ok || !result.success) {
                        throw new Error(result.message || 'Gagal menghapus data parsil.');
                    }

                    editableLayer.removeLayer(layer);
                    map.closePopup();
                } catch (error) {
                    setStatus(popupStatus, error.message || 'Gagal menghapus data.', 'error');
                    deleteButton.disabled = false;
                }
            });
        });
    }

    async function loadRoads() {
        const response = await fetch('api/road_read.php', {
            headers: {
                'Accept': 'application/json'
            }
        });

        const result = await parseJsonResponse(response);
        if (!response.ok || !result.success) {
            throw new Error(result.message || 'Gagal memuat data jalan.');
        }

        result.data.forEach((item) => {
            if (!item.geometry_geojson) {
                return;
            }

            const layer = L.geoJSON(item.geometry_geojson).getLayers()[0];
            if (!layer) {
                return;
            }

            layer.featureType = 'road';
            layer.featureId = item.id;
            layer.featureProps = {
                nama_jalan: item.nama_jalan,
                status: item.status,
                panjang_meter: item.panjang_meter
            };

            attachRoadPopup(layer);
            editableLayer.addLayer(layer);
        });
    }

    async function loadParcels() {
        const response = await fetch('api/parcel_read.php', {
            headers: {
                'Accept': 'application/json'
            }
        });

        const result = await parseJsonResponse(response);
        if (!response.ok || !result.success) {
            throw new Error(result.message || 'Gagal memuat data parsil.');
        }

        result.data.forEach((item) => {
            if (!item.geometry_geojson) {
                return;
            }

            const layer = L.geoJSON(item.geometry_geojson).getLayers()[0];
            if (!layer) {
                return;
            }

            layer.featureType = 'parcel';
            layer.featureId = item.id;
            layer.featureProps = {
                nama_pemilik: item.nama_pemilik,
                status_kepemilikan: item.status_kepemilikan,
                luas_m2: item.luas_m2
            };

            attachParcelPopup(layer);
            editableLayer.addLayer(layer);
        });
    }

    const drawControl = new L.Control.Draw({
        position: 'topleft',
        draw: {
            polyline: {
                shapeOptions: {
                    color: '#dc2626',
                    weight: 5
                }
            },
            polygon: {
                allowIntersection: false,
                showArea: true,
                shapeOptions: {
                    color: '#ea580c',
                    fillOpacity: 0.35,
                    weight: 3
                }
            },
            rectangle: false,
            circle: false,
            marker: false,
            circlemarker: false
        },
        edit: {
            featureGroup: editableLayer,
            remove: true
        }
    });

    map.addControl(drawControl);

    map.on(L.Draw.Event.CREATED, (event) => {
        const layer = event.layer;
        const geometryType = event.layerType;

        editableLayer.addLayer(layer);

        if (geometryType === 'polyline') {
            openRoadModal(layer, 'create', null);
            return;
        }

        if (geometryType === 'polygon') {
            openParcelModal(layer, 'create', null);
            return;
        }

        editableLayer.removeLayer(layer);
    });

    map.on(L.Draw.Event.EDITED, async (event) => {
        const layers = event.layers.getLayers();

        for (const layer of layers) {
            try {
                if (layer.featureType === 'road') {
                    const lengthMeters = calculatePolylineLengthMeters(layer.getLatLngs());
                    const payload = {
                        id: layer.featureId,
                        nama_jalan: layer.featureProps.nama_jalan,
                        status: layer.featureProps.status,
                        panjang_meter: Number(lengthMeters.toFixed(2)),
                        wkt: polylineToWkt(layer.getLatLngs())
                    };

                    const response = await fetch('api/road_update.php', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json'
                        },
                        body: JSON.stringify(payload)
                    });

                    const result = await parseJsonResponse(response);
                    if (!response.ok || !result.success) {
                        throw new Error(result.message || 'Gagal update geometri jalan.');
                    }

                    layer.featureProps.panjang_meter = payload.panjang_meter;
                    attachRoadPopup(layer);
                }

                if (layer.featureType === 'parcel') {
                    const areaM2 = calculatePolygonAreaMeters(layer.getLatLngs()[0]);
                    const payload = {
                        id: layer.featureId,
                        nama_pemilik: layer.featureProps.nama_pemilik,
                        status_kepemilikan: layer.featureProps.status_kepemilikan,
                        luas_m2: Number(areaM2.toFixed(2)),
                        wkt: polygonToWkt(layer.getLatLngs()[0])
                    };

                    const response = await fetch('api/parcel_update.php', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Accept': 'application/json'
                        },
                        body: JSON.stringify(payload)
                    });

                    const result = await parseJsonResponse(response);
                    if (!response.ok || !result.success) {
                        throw new Error(result.message || 'Gagal update geometri parsil.');
                    }

                    layer.featureProps.luas_m2 = payload.luas_m2;
                    attachParcelPopup(layer);
                }
            } catch (error) {
                window.alert(error.message || 'Gagal menyimpan update geometri.');
            }
        }
    });

    map.on(L.Draw.Event.DELETED, async (event) => {
        const layers = event.layers.getLayers();

        for (const layer of layers) {
            if (!layer.featureType || !layer.featureId) {
                continue;
            }

            try {
                const endpoint = layer.featureType === 'road' ? 'api/road_delete.php' : 'api/parcel_delete.php';
                const response = await fetch(endpoint, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ id: layer.featureId })
                });

                const result = await parseJsonResponse(response);
                if (!response.ok || !result.success) {
                    throw new Error(result.message || 'Gagal menghapus data.');
                }
            } catch (error) {
                window.alert(error.message || 'Gagal sinkron delete ke database.');
            }
        }
    });

    featureForm.addEventListener('submit', async (event) => {
        event.preventDefault();
        if (!pendingLayer || !pendingType) {
            return;
        }

        setStatus(formStatus, 'Menyimpan data...', '');

        try {
            if (pendingType === 'road') {
                const namaJalan = document.getElementById('nama_jalan').value.trim();
                const statusJalan = document.getElementById('status_jalan').value;
                const panjangMeter = Number(document.getElementById('panjang_meter').value);
                const wkt = polylineToWkt(pendingLayer.getLatLngs());

                const endpoint = pendingMode === 'create' ? 'api/road_create.php' : 'api/road_update.php';
                const payload = {
                    nama_jalan: namaJalan,
                    status: statusJalan,
                    panjang_meter: panjangMeter,
                    wkt: wkt
                };

                if (pendingMode === 'update') {
                    payload.id = pendingLayer.featureId;
                }

                const response = await fetch(endpoint, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify(payload)
                });

                const result = await parseJsonResponse(response);
                if (!response.ok || !result.success) {
                    throw new Error(result.message || 'Gagal menyimpan data jalan.');
                }

                pendingLayer.featureType = 'road';
                pendingLayer.featureId = pendingMode === 'create' ? result.id : pendingLayer.featureId;
                pendingLayer.featureProps = {
                    nama_jalan: namaJalan,
                    status: statusJalan,
                    panjang_meter: panjangMeter
                };
                attachRoadPopup(pendingLayer);
            }

            if (pendingType === 'parcel') {
                const namaPemilik = document.getElementById('nama_pemilik').value.trim();
                const statusKepemilikan = document.getElementById('status_kepemilikan').value;
                const luasM2 = Number(document.getElementById('luas_m2').value);
                const wkt = polygonToWkt(pendingLayer.getLatLngs()[0]);

                const endpoint = pendingMode === 'create' ? 'api/parcel_create.php' : 'api/parcel_update.php';
                const payload = {
                    nama_pemilik: namaPemilik,
                    status_kepemilikan: statusKepemilikan,
                    luas_m2: luasM2,
                    wkt: wkt
                };

                if (pendingMode === 'update') {
                    payload.id = pendingLayer.featureId;
                }

                const response = await fetch(endpoint, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify(payload)
                });

                const result = await parseJsonResponse(response);
                if (!response.ok || !result.success) {
                    throw new Error(result.message || 'Gagal menyimpan data parsil.');
                }

                pendingLayer.featureType = 'parcel';
                pendingLayer.featureId = pendingMode === 'create' ? result.id : pendingLayer.featureId;
                pendingLayer.featureProps = {
                    nama_pemilik: namaPemilik,
                    status_kepemilikan: statusKepemilikan,
                    luas_m2: luasM2
                };
                attachParcelPopup(pendingLayer);
            }

            setStatus(formStatus, 'Data berhasil disimpan.', 'success');
            setTimeout(() => closeModal(false), 350);
        } catch (error) {
            setStatus(formStatus, error.message || 'Gagal menyimpan data.', 'error');
        }
    });

    cancelButton.addEventListener('click', () => closeModal(true));
    modalBackdrop.addEventListener('click', (event) => {
        if (event.target === modalBackdrop) {
            closeModal(true);
        }
    });

    try {
        await loadRoads();
        await loadParcels();

        if (editableLayer.getLayers().length > 0) {
            map.fitBounds(editableLayer.getBounds().pad(0.2));
        }
    } catch (error) {
        window.alert(error.message || 'Gagal memuat data spasial.');
    }
});
