/* ============================================================
   WebGIS - app.js
   Sistem Informasi Geografis Pengentasan Kemiskinan
============================================================ */
(function () {
'use strict';

/* -- Konfigurasi ----------------------------------------- */
const DEFAULT_CENTER = [-0.05754868797441759, 109.32739998281652];
const DEFAULT_ZOOM   = 14;

/* -- State Aplikasi -------------------------------------- */
let clickTimer = null; // Timer untuk membedakan single click & double click
let mode = 'point';           // mode aktif saat ini
let deleteCallback = null;    // callback untuk konfirmasi hapus

// Preview sementara di peta
let previewMarker  = null;
let previewCircle  = null;
let previewLine    = null;
let previewPolygon = null;
let previewVertices = [];

// Data untuk drawing
let jalanLatLngs   = [];
let polygonLatLngs = [];

// Data runtime
let fasilitasPublikList = [];   // [{id, nama, lat, lng, radius}, ...]
let pendudukList    = [];   // [{data, marker}, ...]

/* -- Layer Groups ---------------------------------------- */
let geoJalanLayer    = null;
let geoKecamatanLayer= null;
let geoSungaiLayer   = null;

const lgFasilitasPublik = L.layerGroup();
const lgPendudukDalam   = L.layerGroup();
const lgPendudukLuar    = L.layerGroup();
const lgSpbu24          = L.layerGroup();
const lgSpbuTidak       = L.layerGroup();
const lgJalan           = L.layerGroup();
const lgPolygon     = L.layerGroup();

/* -- Inisialisasi Peta ----------------------------------- */
const savedCenter = (() => {
  try { return JSON.parse(localStorage.getItem('webgis_center')); } catch { return null; }
})();
const savedZoom = parseInt(localStorage.getItem('webgis_zoom') || '0', 10) || DEFAULT_ZOOM;

const map = L.map('map', {
  doubleClickZoom: false,
  zoomControl: true
}).setView(savedCenter || DEFAULT_CENTER, savedZoom);

// Base tile (Premium CARTO Positron for SaaS look)
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
  maxZoom: 19,
  attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
}).addTo(map);

// Scale control
L.control.scale({ imperial: false, metric: true, position: 'bottomleft' }).addTo(map);

// Simpan posisi peta
map.on('moveend zoomend', () => {
  const c = map.getCenter();
  localStorage.setItem('webgis_center', JSON.stringify([c.lat, c.lng]));
  localStorage.setItem('webgis_zoom', String(map.getZoom()));
});

// Inisialisasi Lottie Splash Screen
const splashEl = document.getElementById('splashScreen');
if (splashEl && window.lottie) {
  lottie.loadAnimation({
    container: document.getElementById('lottieContainer'),
    renderer: 'svg',
    loop: true,
    autoplay: true,
    path: 'assets/animasi-lokasi.json'
  });
}

// Sembunyikan loading setelah peta siap
map.whenReady(() => {
  setTimeout(() => {
    const ml = el('mapLoading');
    if(ml) ml.classList.add('hidden');
  }, 600);
  
  // Sembunyikan Splash Screen dengan efek fade-out yang mulus
  if (splashEl) {
    setTimeout(() => {
      splashEl.classList.add('splash-hidden');
      setTimeout(() => splashEl.remove(), 500); // Hapus elemen setelah transisi opacity 0.5s selesai
    }, 1500); // Delay 1.5 detik agar preloader premium sempat dinikmati user
  }
});

/* -- Tambahkan layer groups ke peta ---------------------- */
[lgFasilitasPublik, lgPendudukDalam, lgPendudukLuar].forEach(lg => lg.addTo(map));
if (document.getElementById("layerSpbu24") && document.getElementById("layerSpbu24").checked) lgSpbu24.addTo(map);
if (document.getElementById("layerSpbuTidak") && document.getElementById("layerSpbuTidak").checked) lgSpbuTidak.addTo(map);
if (document.getElementById("layerJalan") && document.getElementById("layerJalan").checked) lgJalan.addTo(map);
if (document.getElementById("layerPolygon") && document.getElementById("layerPolygon").checked) lgPolygon.addTo(map);

/* -------------------------------------------------------
   HELPER FUNCTIONS
------------------------------------------------------- */

function el(id) { return document.getElementById(id); }

function showToast(message, type = 'success', duration = 3500) {
  const container = el('toastContainer');
  const toast = document.createElement('div');
  const icons = { success: '\u2713', error: '\u2715', info: '\u2139', warning: '\u26A0' };
  toast.className = `toast ${type}`;
  toast.innerHTML = `<span>${icons[type] || '\u2022'}</span><span>${message}</span>`;
  container.appendChild(toast);
  setTimeout(() => {
    toast.classList.add('fade-out');
    setTimeout(() => toast.remove(), 350);
  }, duration);
}

function showDeleteConfirm(message, callback) {
  el('deleteMessage').textContent = message;
  deleteCallback = callback;
  showModal('deleteModal');
}

function showModal(id) {
  el('modalBackdrop').classList.remove('hidden');
  el(id).classList.remove('hidden');
}

function hideModal(id) {
  el(id).classList.add('hidden');
  // sembunyikan backdrop hanya jika tidak ada modal lain terbuka
  const openModals = document.querySelectorAll('.modal:not(.hidden)');
  if (openModals.length === 0) {
    el('modalBackdrop').classList.add('hidden');
  }
}

function hideAllModals() {
  document.querySelectorAll('.modal').forEach(m => m.classList.add('hidden'));
  el('modalBackdrop').classList.add('hidden');
}

function setHelpText(text) {
  el('helpText').textContent = text;
}

/* -- Kalkulasi Geospasial -------------------------------- */

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

function hitungLuas(latlngs) {
  if (latlngs.length < 3) return 0;
  const pts = latlngs.map(ll => map.options.crs.project(ll));
  let area = 0;
  for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {
    area += (pts[j].x * pts[i].y) - (pts[i].x * pts[j].y);
  }
  return Math.abs(area / 2);
}

function getDistanceMeter(lat1, lng1, lat2, lng2) {
  return L.latLng(lat1, lng1).distanceTo(L.latLng(lat2, lng2));
}

function cekJangkauan(lat, lng) {
  let hasil = { status: 'Luar Jangkauan', id: '', nama: '' };
  let minDistance = Infinity;

  fasilitasPublikList.forEach(ri => {
    const d = getDistanceMeter(lat, lng, parseFloat(ri.latitude), parseFloat(ri.longitude));
    if (d <= parseFloat(ri.radius) && d < minDistance) {
      minDistance = d;
      hasil = { status: 'Dalam Jangkauan', id: ri.id, nama: ri.nama };
    }
  });
  return hasil;
}

/* -- GeoJSON helpers ------------------------------------- */

function toLineFeature(latlngs, props = {}) {
  return {
    type: 'Feature',
    geometry: { type: 'LineString', coordinates: latlngs.map(ll => [ll.lng, ll.lat]) },
    properties: props
  };
}

function toPolygonFeature(latlngs, props = {}) {
  const ring = latlngs.map(ll => [ll.lng, ll.lat]);
  if (ring.length && (ring[0][0] !== ring[ring.length - 1][0] || ring[0][1] !== ring[ring.length - 1][1])) {
    ring.push([ring[0][0], ring[0][1]]);
  }
  return {
    type: 'Feature',
    geometry: { type: 'Polygon', coordinates: [ring] },
    properties: props
  };
}

function lineFeatureToLatLngs(feat) {
  if (!feat?.geometry?.coordinates) return [];
  return feat.geometry.coordinates.map(c => [c[1], c[0]]);
}

function polygonFeatureToLatLngs(feat) {
  if (!feat?.geometry?.coordinates?.[0]) return [];
  const ring = [...feat.geometry.coordinates[0]];
  if (ring.length > 1) {
    const f = ring[0], l = ring[ring.length - 1];
    if (f[0] === l[0] && f[1] === l[1]) ring.pop();
  }
  return ring.map(c => [c[1], c[0]]);
}

/* -- Warna Helper ---------------------------------------- */

function warnaJalan(status) {
  return { 'Jalan Nasional': '#d32f2f', 'Jalan Provinsi': '#f57c00', 'Jalan Kabupaten': '#388e3c' }[status] || '#1565c0';
}

function warnaPolygon(status) {
  return { 'SHM': '#1b5e20', 'HGB': '#1565c0', 'HGU': '#ef6c00', 'HP': '#6a1b9a' }[status] || '#455a64';
}

function warnaKecamatan(nama) {
  const colors = {
    'Pontianak Barat': '#e41a1c', 'Pontianak Timur': '#377eb8',
    'Pontianak Utara': '#4daf4a', 'Pontianak Selatan': '#984ea3',
    'Pontianak Kota': '#ff7f00', 'Pontianak Tenggara': '#a65628'
  };
  return colors[nama] || '#888888';
}

/* -- Custom Marker Icons --------------------------------- */

function createFPIcon() {
  const svg = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="2" width="16" height="20" rx="2" ry="2"></rect><line x1="9" y1="22" x2="9" y2="16"></line><line x1="15" y1="22" x2="15" y2="16"></line><line x1="9" y1="16" x2="15" y2="16"></line><circle cx="8" cy="6" r="1"></circle><circle cx="16" cy="6" r="1"></circle><circle cx="8" cy="11" r="1"></circle><circle cx="16" cy="11" r="1"></circle></svg>`;
  return L.divIcon({
    className: '',
    html: `<div class="custom-marker fp-marker"><div class="marker-icon">${svg}</div></div>`,
    iconSize: [32, 32],
    iconAnchor: [16, 32],
    popupAnchor: [0, -34]
  });
}

function createPointIcon(is24) {
  const markerClass = is24 ? 'point-marker-24' : 'point-marker-normal';
  const svg = `<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="1.5"></circle></svg>`;
  return L.divIcon({
    className: '',
    html: `<div class="custom-marker ${markerClass}"><div class="marker-icon">${svg}</div></div>`,
    iconSize: [26, 26],
    iconAnchor: [13, 26],
    popupAnchor: [0, -28]
  });
}

function createPendudukIcon(isDalam) {
  const colorClass = isDalam ? 'pm-marker-dalam' : 'pm-marker-luar';
  const svg = `<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>`;
  return L.divIcon({
    className: '',
    html: `<div class="custom-marker ${colorClass}"><div class="marker-icon">${svg}</div></div>`,
    iconSize: [28, 28],
    iconAnchor: [14, 28],
    popupAnchor: [0, -30]
  });
}

/* -------------------------------------------------------
   PREVIEW MANAGEMENT
------------------------------------------------------- */

function clearAllPreview() {
  if (previewMarker)  { map.removeLayer(previewMarker);  previewMarker  = null; }
  if (previewCircle)  { map.removeLayer(previewCircle);  previewCircle  = null; }
  if (previewLine)    { map.removeLayer(previewLine);    previewLine    = null; }
  if (previewPolygon) { map.removeLayer(previewPolygon); previewPolygon = null; }
  previewVertices.forEach(v => map.removeLayer(v));
  previewVertices = [];
  jalanLatLngs   = [];
  polygonLatLngs = [];
}

function addVertexMarker(latlng, color = '#1565c0') {
  const v = L.circleMarker(latlng, {
    radius: 5, color, fillColor: color,
    fillOpacity: 1, weight: 2
  }).addTo(map);
  previewVertices.push(v);
  return v;
}

function updateJalanPreview() {
  if (previewLine)    { map.removeLayer(previewLine); previewLine = null; }
  previewVertices.forEach(v => map.removeLayer(v));
  previewVertices = [];

  jalanLatLngs.forEach((ll, i) => {
    const v = addVertexMarker(ll, '#d32f2f');
    v.bindTooltip(`Titik ${i + 1}`, { direction: 'top', permanent: false });
  });

  if (jalanLatLngs.length >= 2) {
    previewLine = L.polyline(jalanLatLngs, { color: '#d32f2f', weight: 4, opacity: 0.9 }).addTo(map);
    el('panjang_meter').value = hitungPanjang(jalanLatLngs).toFixed(2);
  }
  el('jumlah_titik_jalan').value = jalanLatLngs.length;
  el('koordinat_jalan').value = JSON.stringify(toLineFeature(jalanLatLngs), null, 2);
}

function updatePolygonPreview() {
  if (previewPolygon) { map.removeLayer(previewPolygon); previewPolygon = null; }
  previewVertices.forEach(v => map.removeLayer(v));
  previewVertices = [];

  polygonLatLngs.forEach((ll, i) => {
    const v = addVertexMarker(ll, '#6a1b9a');
    v.bindTooltip(`Titik ${i + 1}`, { direction: 'top', permanent: false });
  });

  if (polygonLatLngs.length >= 3) {
    previewPolygon = L.polygon(polygonLatLngs, {
      color: '#6a1b9a', fillColor: '#ba68c8', fillOpacity: 0.3, weight: 3
    }).addTo(map);
    el('luas_tanah').value = hitungLuas(polygonLatLngs).toFixed(4);
  }
  el('jumlah_titik_polygon').value = polygonLatLngs.length;
  el('koordinat_polygon').value = JSON.stringify(toPolygonFeature(polygonLatLngs), null, 2);
}

/* -------------------------------------------------------
   MODE MANAGEMENT
------------------------------------------------------- */

const MODES = {
  point:          { btn: 'btnToolPoint',      help: 'Klik pada peta untuk menambah titik.' },
  jalan:          { btn: 'btnToolJalan',      help: 'Klik titik-titik jalan. Double-klik untuk selesai. Klik-kanan untuk hapus titik terakhir.' },
  polygon:        { btn: 'btnToolPolygon',    help: 'Klik titik-titik polygon. Double-klik untuk selesai. Klik-kanan untuk hapus titik terakhir.' },
  fasilitas_publik:   { btn: 'btnToolFasilitasPublik',help: 'Klik pada peta untuk menentukan lokasi Fasilitas Publik.' },
  penduduk_miskin:{ btn: 'btnToolPenduduk',   help: 'Klik pada peta untuk menentukan lokasi penduduk miskin.' },
  lokasi:         { btn: 'btnToolLokasi',     help: 'Mencari lokasi Anda...' },
};

function setMode(newMode) {
  clearAllPreview();
  hideAllModals();

  mode = newMode;

  // Update active button
  document.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active'));
  const cfg = MODES[newMode];
  if (cfg) {
    const btn = el(cfg.btn);
    if (btn) btn.classList.add('active');
    setHelpText(cfg.help);
  }

  // Khusus lokasi: langsung trigger
  if (newMode === 'lokasi') {
    map.locate({ setView: true, maxZoom: 18 });
    if (el('btnToolPoint')) {
      mode = 'point'; // kembali ke point setelah locate
      el('btnToolPoint').classList.add('active');
    } else {
      mode = 'view';
    }
    if (el('btnToolLokasi')) el('btnToolLokasi').classList.remove('active');
  }
}

/* -------------------------------------------------------
   RENDER FUNCTIONS
------------------------------------------------------- */

/* -- Render Point ---------------------------------------- */
function renderPoint(item) {
  const lat = parseFloat(item.latitude);
  const lng = parseFloat(item.longitude);
  const is24 = item.buka_24_jam === 'Ya';

  const marker = L.marker([lat, lng], { 
      icon: createPointIcon(is24),
      draggable: (typeof USER_ROLE !== 'undefined' && USER_ROLE !== 'guest')
  }).addTo(is24 ? lgSpbu24 : lgSpbuTidak);

  marker.on('dragend', function(e) {
      const pos = e.target.getLatLng();
      updateLocation('point', item.id, pos.lat, pos.lng, item.nama);
  });

  const popup = `
    <div class="popup-card">
      <div class="popup-title">&#x1F4CD; ${item.nama}</div>
      <div class="popup-row"><strong>No. WA</strong><span>${item.no_wa}</span></div>
      <div class="popup-row"><strong>24 Jam</strong><span>${item.buka_24_jam}</span></div>
    </div>
    <div class="popup-actions">
      <button class="popup-btn" onclick="editPoint(${item.id})">&#x270F;&#xFE0F; Edit</button>
      <button class="popup-btn del" onclick="hapusData('point',${item.id},'Hapus titik ${item.nama}?')">&#x1F5D1; Hapus</button>
    </div>`;

  marker.bindPopup(popup, { maxWidth: 280 });
  return marker;
}

/* -- GLOBAL: EDIT Point / SPBU --------------------------- */
window.editPoint = function (id) {
  fetch(`api/get_point.php?id=${id}`)
    .then(r => r.json())
    .then(res => {
      if (res.status === 'success') {
        const d = res.data;
        el('point_id').value = d.id;
        el('point_nama').value = d.nama;
        el('point_no_wa').value = d.no_wa;
        
        // Handle radio buttons
        if (d.buka_24_jam === 'Ya') {
            document.querySelector('input[name="point_buka_24_jam"][value="Ya"]').checked = true;
        } else {
            document.querySelector('input[name="point_buka_24_jam"][value="Tidak"]').checked = true;
        }
        
        // Populate coordinates
        el('point_latitude').value = d.latitude;
        el('point_longitude').value = d.longitude;
        
        el('pointModalTitle').textContent = 'Edit Titik';

        // Preview di peta
        const tempGeom = { lat: parseFloat(d.latitude), lng: parseFloat(d.longitude) };
        if (previewMarker) map.removeLayer(previewMarker);
        previewMarker = L.marker([tempGeom.lat, tempGeom.lng], {
          icon: createPointIcon(d.buka_24_jam === 'Ya')
        }).addTo(map);
        map.setView([tempGeom.lat, tempGeom.lng], 16);

        el('pointModal').classList.remove('hidden');
        el('modalBackdrop').classList.remove('hidden');
        } else {
          showAlert('Gagal', res.message || 'Gagal mengambil data');
        }
      })
      .catch(e => {
        console.error(e);
        showAlert('Terjadi Kesalahan', 'Error: ' + e.toString() + '. Mohon segarkan (refresh) halaman.');
      });
  };

/* -- Render Jalan ---------------------------------------- */
function renderJalan(item) {
  try {
    const feat = JSON.parse(item.koordinat);
    const coords = lineFeatureToLatLngs(feat);
    const poly = L.polyline(coords, {
      color: warnaJalan(item.status_jalan), weight: 5, opacity: 0.85
    }).addTo(lgJalan);

    const popup = `
      <div class="popup-card">
        <div class="popup-title">&#x1F6E3;&#xFE0F; ${item.nama_jalan}</div>
        <div class="popup-row"><strong>Status</strong><span>${item.status_jalan}</span></div>
        <div class="popup-row"><strong>Panjang</strong><span>${parseFloat(item.panjang_meter).toFixed(1)} m</span></div>
      </div>
      <div class="popup-actions">
        <button class="popup-btn del" onclick="hapusData('jalan',${item.id},'Hapus jalan ${item.nama_jalan}?')">&#x1F5D1; Hapus</button>
      </div>`;

    poly.bindPopup(popup, { maxWidth: 280 });
    return poly;
  } catch (e) { console.error('renderJalan error:', e); }
}

/* -- Render Polygon -------------------------------------- */
function renderPolygon(item) {
  try {
    const feat = JSON.parse(item.koordinat);
    const coords = polygonFeatureToLatLngs(feat);
    const warna = warnaPolygon(item.status_kepemilikan);
    const poly = L.polygon(coords, {
      color: warna, fillColor: warna, fillOpacity: 0.3, weight: 3
    }).addTo(lgPolygon);

    const popup = `
      <div class="popup-card">
        <div class="popup-title">&#x1F4D0; ${item.nama_parsil}</div>
        <div class="popup-row"><strong>Status</strong><span>${item.status_kepemilikan}</span></div>
        <div class="popup-row"><strong>Luas</strong><span>${parseFloat(item.luas_tanah).toFixed(2)} m&sup2;</span></div>
      </div>
      <div class="popup-actions">
        <button class="popup-btn del" onclick="hapusData('polygon',${item.id},'Hapus polygon ${item.nama_parsil}?')">&#x1F5D1; Hapus</button>
      </div>`;

    poly.bindPopup(popup, { maxWidth: 280 });
    return poly;
  } catch (e) { console.error('renderPolygon error:', e); }
}

/* -- Render Fasilitas Publik ----------------------------- */
function renderFasilitasPublik(item) {
  const lat = parseFloat(item.latitude);
  const lng = parseFloat(item.longitude);
  const radius = parseFloat(item.radius);

  fasilitasPublikList.push(item);

  const marker = L.marker([lat, lng], { icon: createFPIcon() }).addTo(lgFasilitasPublik);
  const circle = L.circle([lat, lng], {
    radius, color: '#e53935', fillColor: '#ef9a9a',
    fillOpacity: 0.12, weight: 2, dashArray: '6 4',
    interactive: false
  }).addTo(lgFasilitasPublik);

  const popup = `
    <div class="popup-card">
      <div class="popup-title">
        &#x1F3E2; ${item.nama}
        <span class="popup-badge badge-fp">${item.jenis || 'Fasilitas Publik'}</span>
      </div>
      <div class="popup-row"><strong>Alamat</strong><span>${item.alamat || '-'}</span></div>
      <div class="popup-row"><strong>Radius</strong><span>${radius} m</span></div>
      <div class="popup-row"><strong>Kontak</strong><span>${item.kontak || '-'}</span></div>
    </div>
    <div class="popup-actions">
      <button class="popup-btn" onclick="editFasilitasPublik(${item.id})">&#x270F;&#xFE0F; Edit</button>
      <button class="popup-btn del" onclick="hapusData('fasilitas_publik',${item.id},'Hapus ${item.nama}?')">&#x1F5D1; Hapus</button>
    </div>`;

  marker.bindPopup(popup, { maxWidth: 300 });

  return { marker, circle };
}

/* -- Render Penduduk Miskin ------------------------------ */
function renderPenduduk(item) {
  const lat = parseFloat(item.latitude);
  const lng = parseFloat(item.longitude);
  const cek  = cekJangkauan(lat, lng);
  
  // FIX SPASIAL: Pastikan status jangkauan tersimpan di objek item untuk dirender di sidebar
  item.status_jangkauan = cek.status;

  const marker = L.marker([lat, lng], {
    icon: createPendudukIcon(cek.status === 'Dalam Jangkauan'),
    draggable: (typeof USER_ROLE !== 'undefined' && USER_ROLE !== 'guest')
  }).addTo(cek.status === 'Dalam Jangkauan' ? lgPendudukDalam : lgPendudukLuar);

  marker.on('dragend', function(e) {
      const pos = e.target.getLatLng();
      updateLocation('penduduk_miskin', item.id, pos.lat, pos.lng, item.nama);
  });

  const badgeClass = cek.status === 'Dalam Jangkauan' ? 'badge-dalam' : 'badge-luar';
  
  let fotoHtml = '';
  if (item.foto_rumah) {
    fotoHtml += `<img src="uploads/${item.foto_rumah}" style="width:100%;height:120px;object-fit:cover;border-radius:8px;margin-bottom:8px;">`;
  }
  
  const popup = `
    <div class="popup-card">
      ${fotoHtml}
      <div class="popup-title">
        &#x1F464; ${item.nama}
        <span class="popup-badge ${badgeClass}">${cek.status}</span>
      </div>
      <div class="popup-row"><strong>NIK</strong><span>${item.nik || '-'}</span></div>
      <div class="popup-row"><strong>Ditangani</strong><span>${cek.nama || item.fp_nama || '-'}</span></div>
      <div class="popup-row"><strong>Keterangan</strong><span>${item.keterangan || '-'}</span></div>
    </div>
    <div class="popup-actions">
      <button class="popup-btn" onclick="editPenduduk(${item.id})">&#x270F;&#xFE0F; Edit</button>
      <button class="popup-btn del" onclick="hapusData('penduduk_miskin',${item.id},'Hapus data ${item.nama}?')">&#x1F5D1; Hapus</button>
    </div>`;

  marker.bindPopup(popup, { maxWidth: 300 });

  pendudukList.push({ data: item, marker });
  return marker;
}

/* -- Refresh Status Penduduk ----------------------------- */
function refreshStatusPenduduk() {
  lgPendudukDalam.clearLayers();
  lgPendudukLuar.clearLayers();
  const backup = pendudukList.map(p => p.data);
  pendudukList = [];
  backup.forEach(item => renderPenduduk(item));
  updateDashboardStats(); // Panggil fungsi update stat
}

/* -- Update Statistik Dashboard Secara Real-Time --------- */
function updateDashboardStats() {
  const totalFP = fasilitasPublikList.length;
  const totalPM = pendudukList.length;
  
  let ditangani = 0;
  pendudukList.forEach(p => {
    const cek = cekJangkauan(parseFloat(p.data.latitude), parseFloat(p.data.longitude));
    if (cek.status === 'Dalam Jangkauan') ditangani++;
  });
  
  const belum = totalPM - ditangani;
  const persen = totalPM > 0 ? ((ditangani / totalPM) * 100).toFixed(1) : 0;

  // Update SPBU Stats
  if (el('statTotalSPBU')) {
    const totalSPBU = APP_DATA.points.length;
    let spbu24 = 0;
    APP_DATA.points.forEach(p => { if (p.buka_24_jam === 'Ya') spbu24++; });
    const spbuTidak = totalSPBU - spbu24;
    el('statTotalSPBU').textContent = totalSPBU;
    if (el('statSPBU24')) el('statSPBU24').textContent = spbu24;
    if (el('statSPBUTidak')) el('statSPBUTidak').textContent = spbuTidak;
  }

  // Update angka di HTML
  if (el('statTotalRI')) el('statTotalRI').textContent = totalFP;
  if (el('statTotalPM')) el('statTotalPM').textContent = totalPM;
  if (el('statDitangani')) el('statDitangani').textContent = ditangani;
  if (el('statBelum')) el('statBelum').textContent = belum;
  if (el('statPersen')) el('statPersen').textContent = persen + '%';
  if (el('statProgressBar')) el('statProgressBar').style.width = persen + '%';
}

/* -- Real-Time Refresh Data (Modul Bantuan) -------------- */
async function refreshDataModul() {
  try {
    const res = await fetch('api/get_all_bantuan.php');
    const json = await res.json();
    if (json.status === 'success') {
      // 1. Update data global
      APP_DATA.fasilitasPublik = json.fasilitasPublik;
      APP_DATA.pendudukMiskin = json.pendudukMiskin;
      
      // 2. Clear layer peta
      lgFasilitasPublik.clearLayers();
      lgPendudukDalam.clearLayers();
      lgPendudukLuar.clearLayers();
      
      // 3. Reset array data lokal
      fasilitasPublikList = [];
      pendudukList = [];
      
      // 4. Render ulang marker (renderPenduduk akan otomatis hitung jarak spasial terbaru)
      APP_DATA.fasilitasPublik.forEach(renderFasilitasPublik);
      APP_DATA.pendudukMiskin.forEach(renderPenduduk);
      
      // 5. Update stat & panel data
      updateDashboardStats();
      if(window.__rebuildCards) window.__rebuildCards();
    }
  } catch (err) {
    console.error('Gagal me-refresh data bantuan:', err);
  }
}

/* -------------------------------------------------------
   LOAD DATA AWAL
------------------------------------------------------- */
(APP_DATA.points || []).forEach(renderPoint);
(APP_DATA.jalan  || []).forEach(renderJalan);
(APP_DATA.polygons || []).forEach(renderPolygon);
(APP_DATA.fasilitasPublik || []).forEach(renderFasilitasPublik);
(APP_DATA.pendudukMiskin || []).forEach(renderPenduduk);

/* -------------------------------------------------------
   LOAD GEOJSON EKSTERNAL
------------------------------------------------------- */

function loadGeoJSON(url, options = {}) {
  return fetch(url)
    .then(r => { if (!r.ok) throw new Error('Gagal load: ' + url); return r.json(); })
    .then(geojson => {
      const layer = L.geoJSON(geojson, {
        style: feat => {
          const t = feat.geometry?.type || '';
          if (t === 'Polygon' || t === 'MultiPolygon') {
            let fill = options.fillColor || '#42a5f5';
            if (options.dynamicColor && feat.properties) {
              const nm = feat.properties.Ket || feat.properties.WADMKC ||
                         feat.properties.KECAMATAN || feat.properties.nama || '';
              fill = warnaKecamatan(nm);
            }
            return { color: '#333', weight: 1.5, fillColor: fill, fillOpacity: 0.35 };
          }
          if (t === 'LineString' || t === 'MultiLineString') {
            return { color: options.color || '#1565c0', weight: options.weight || 2, opacity: 0.9 };
          }
          return { color: options.color || '#1565c0' };
        },
        pointToLayer: (feat, latlng) => L.circleMarker(latlng, {
          radius: 4, color: options.color || '#1565c0',
          fillColor: options.fillColor || '#42a5f5', fillOpacity: 0.9, weight: 1
        }),
        onEachFeature: (feat, layer) => {
          if (!feat.properties) return;
          let html = `<div class="popup-card"><div class="popup-title">${options.title || 'GeoJSON'}</div>`;
          Object.entries(feat.properties).forEach(([k, v]) => {
            if (v) html += `<div class="popup-row"><strong>${k}</strong><span>${v}</span></div>`;
          });
          html += '</div>';
          layer.bindPopup(html, { maxWidth: 280 });
        }
      });

      if (options.adjustWeight) {
        map.on('zoomend', () => {
          const z = map.getZoom();
          const w = z <= 12 ? 0.8 : z <= 14 ? 1.5 : z <= 16 ? 2 : 3;
          layer.setStyle({ weight: w });
        });
      }

      if (options.addToMap !== false) { layer.addTo(map); if (options.fitBounds) map.fitBounds(layer.getBounds()); } return layer;
    })
    .catch(err => { console.warn(err.message); return null; });
}

Promise.all([
  loadGeoJSON('data/Sungai_Besar.geojson', {
    title: 'Sungai Besar', color: '#0d47a1', fillColor: '#90caf9',
    weight: 2, fitBounds: false, addToMap: false
  }),
  loadGeoJSON('data/Admin_Kecamatan.geojson', {
    title: 'Admin Kecamatan', dynamicColor: true,
    color: '#ef6c00', weight: 1.5, fitBounds: false, addToMap: false
  }),
  loadGeoJSON('data/Jaringan_Jalan.geojson', {
    title: 'Jaringan Jalan', color: '#d32f2f',
    weight: 1.5, fitBounds: false, adjustWeight: true, addToMap: false
  })
]).then(([sungai, kecamatan, jalan]) => {
  geoSungaiLayer    = sungai;
  geoKecamatanLayer = kecamatan;
  geoJalanLayer     = jalan;
  
  if (el('layerSungai') && el('layerSungai').checked && geoSungaiLayer) geoSungaiLayer.addTo(map);
  if (el('layerKecamatan') && el('layerKecamatan').checked && geoKecamatanLayer) geoKecamatanLayer.addTo(map);
  if (el('layerGeoJalan') && el('layerGeoJalan').checked && geoJalanLayer) geoJalanLayer.addTo(map);
});

/* -------------------------------------------------------
   REVERSE GEOCODING
------------------------------------------------------- */

function reverseGeocode(lat, lng) {
  if (el('fp_alamat')) el('fp_alamat').value = '';
  if (el('pm_alamat')) el('pm_alamat').value = '';
  
  const statusEl = el('geocodeStatus');
  if (statusEl) statusEl.textContent = '\u23F3 Mencari alamat...';

  fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&accept-language=id`)
    .then(r => r.json())
    .then(data => {
      const alamat = data.display_name || 'Alamat tidak ditemukan';
      if (el('fp_alamat')) el('fp_alamat').value = alamat;
      if (el('pm_alamat')) el('pm_alamat').value = alamat;
      if (statusEl) {
        statusEl.textContent = '\u2713';
        setTimeout(() => { statusEl.textContent = ''; }, 2000);
      }
    })
    .catch(() => {
      if (el('fp_alamat')) el('fp_alamat').value = 'Gagal mengambil alamat';
      if (el('pm_alamat')) el('pm_alamat').value = 'Gagal mengambil alamat';
      if (statusEl) statusEl.textContent = '\u2715';
    });
}

/* -------------------------------------------------------
   MAP EVENT HANDLERS
------------------------------------------------------- */

map.on('click', e => {
  const { lat, lng } = e.latlng;

  // Mode yang tidak perlu timer (langsung eksekusi)
  if (mode === 'point') {
    clearAllPreview();
    el('point_id').value = '';
    el('point_nama').value = '';
    el('point_no_wa').value = '';
    el('point_latitude').value = lat.toFixed(10);
    el('point_longitude').value = lng.toFixed(10);
    document.querySelector('input[name="point_buka_24_jam"][value="Tidak"]').checked = true;
    el('pointModalTitle').textContent = 'Tambah Titik';

    previewMarker = L.marker(e.latlng, { icon: createPointIcon(false) }).addTo(map);
    showModal('pointModal');
    return;
  }

  if (mode === 'fasilitas_publik') {
    el('fp_id').value = '';
    el('fp_nama').value = '';
    el('fp_jenis').value = 'Masjid';
    el('fp_kontak').value = '';
    el('fp_radius').value = 300;
    el('fp_radius_text').textContent = '300';
    el('fp_latitude').value  = lat.toFixed(10);
    el('fp_longitude').value = lng.toFixed(10);
    el('fpModalTitle').textContent = 'Tambah Fasilitas Publik';

    if (previewMarker) map.removeLayer(previewMarker);
    if (previewCircle) map.removeLayer(previewCircle);
    previewMarker = L.marker(e.latlng, { icon: createFPIcon() }).addTo(map);
    previewCircle = L.circle(e.latlng, {
      radius: 300, color: '#e53935', fillColor: '#ef9a9a',
      fillOpacity: 0.12, weight: 2, dashArray: '6 4'
    }).addTo(map);

    reverseGeocode(lat, lng);
    showModal('fasilitasPublikModal');
    return;
  }

  if (mode === 'penduduk_miskin') {
    el('pm_id').value = '';
    el('pm_nama').value = '';
    el('pm_nik').value = '';
    el('pm_keterangan').value = '';
    el('pm_latitude').value  = lat.toFixed(10);
    el('pm_longitude').value = lng.toFixed(10);
    el('pmModalTitle').textContent = 'Tambah Penduduk Miskin';

    const cek = cekJangkauan(lat, lng);
    updateStatusJangkauan(cek);    if (previewMarker) map.removeLayer(previewMarker);
    previewMarker = L.marker(e.latlng, {
      icon: createPendudukIcon(cek.status === 'Dalam Jangkauan')
    }).addTo(map);
    reverseGeocode(lat, lng);
    showModal('pendudukModal');
    return;
  }

  // Khusus mode Menggambar (Jalan & Polygon), gunakan Timer
  if (mode === 'jalan' || mode === 'polygon') {
    if (clickTimer) clearTimeout(clickTimer); // Hapus timer lama jika ada klik berdekatan
    
    clickTimer = setTimeout(() => {
      // Eksekusi jika benar-benar single-click
      if (mode === 'jalan') {
        jalanLatLngs.push(e.latlng);
        updateJalanPreview();
      } else if (mode === 'polygon') {
        polygonLatLngs.push(e.latlng);
        updatePolygonPreview();
      }
    }, 250); // Delay 250 milidetik
  }
});

map.on('dblclick', () => {
  if (clickTimer) {
    clearTimeout(clickTimer); // Batalkan single-click jika terdeteksi double-click
    clickTimer = null;
  }

  if (mode === 'jalan') {
    if (jalanLatLngs.length < 2) { showToast('Minimal 2 titik untuk jalan.', 'warning'); return; }
    updateJalanPreview();
    showModal('jalanModal');
  }
  if (mode === 'polygon') {
    if (polygonLatLngs.length < 3) { showToast('Minimal 3 titik untuk polygon.', 'warning'); return; }
    updatePolygonPreview();
    showModal('polygonModal');
  }
});

map.on('contextmenu', () => {
  if (mode === 'jalan' && jalanLatLngs.length > 0) {
    jalanLatLngs.pop(); updateJalanPreview(); return;
  }
  if (mode === 'polygon' && polygonLatLngs.length > 0) {
    polygonLatLngs.pop(); updatePolygonPreview(); return;
  }
  if (mode === 'point') {
    clearAllPreview();
    hideModal('pointModal');
  }
});

map.on('locationfound', e => {
  showToast('Lokasi ditemukan!', 'success');
  L.marker(e.latlng)
    .addTo(map)
    .bindPopup('<div class="popup-card"><div class="popup-title">&#x1F4E1; Lokasi Saya</div></div>')
    .openPopup();
});

map.on('locationerror', () => {
  showToast('Tidak dapat mengakses lokasi. Pastikan izin lokasi browser aktif.', 'error');
});

document.addEventListener('keydown', e => {
  if (e.key === 'Escape') { clearAllPreview(); hideAllModals(); }
});

/* -------------------------------------------------------
   STATUS JANGKAUAN UI
------------------------------------------------------- */
function updateStatusJangkauan(cek) {
  const elStatus    = el('pm_status');
  const elDitangani = el('pm_ditangani');
  elStatus.textContent = cek.status;
  elStatus.className = 'sj-value ' + (cek.status === 'Dalam Jangkauan' ? 'dalam' : 'luar');
  elDitangani.textContent = cek.nama ? `Ditangani oleh: ${cek.nama}` : 'Tidak dalam jangkauan Fasilitas Publik manapun.';
}

/* -------------------------------------------------------
   TOOL BUTTONS
------------------------------------------------------- */
document.querySelectorAll('.tool-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    const m = btn.dataset.mode;
    if (m) setMode(m);
  });
});

/* -------------------------------------------------------
   SIDEBAR TOGGLE
------------------------------------------------------- */
  /* -- Toggle Sidebar -------------------------------------- */
  const sidebar       = el('sidebar');
  const mapContainer  = el('mapContainer');
  const sidebarOpenBtn= el('sidebarOpenBtn');
  const isMobile      = () => window.innerWidth <= 680;
  
  el('sidebarToggle').addEventListener('click', () => {
    if (isMobile()) {
      sidebar.classList.remove('mobile-open');
    } else {
      sidebar.classList.add('collapsed');
      mapContainer.classList.add('full-width');
      sidebarOpenBtn.classList.remove('hidden');
      map.invalidateSize();
    }
  });
  
  sidebarOpenBtn.addEventListener('click', () => {
    if (isMobile()) {
      sidebar.classList.add('mobile-open');
    } else {
      sidebar.classList.remove('collapsed');
      mapContainer.classList.remove('full-width');
      sidebarOpenBtn.classList.add('hidden');
      map.invalidateSize();
    }
  });

/* -------------------------------------------------------
   LAYER CHECKBOXES
------------------------------------------------------- */
function bindLayerToggle(checkboxId, layerGroup) {
  const cb = el(checkboxId);
  if (!cb) return;
  cb.addEventListener('change', () => {
    if (cb.checked) {
      if (!map.hasLayer(layerGroup)) layerGroup.addTo(map);
    } else {
      map.removeLayer(layerGroup);
    }
  });
}

bindLayerToggle('layerFasilitasPublik',  lgFasilitasPublik);
bindLayerToggle('layerPendudukDalam', lgPendudukDalam);
bindLayerToggle('layerPendudukLuar',  lgPendudukLuar);

bindLayerToggle("layerSpbu24", lgSpbu24);
bindLayerToggle("layerSpbuTidak", lgSpbuTidak);
bindLayerToggle("layerJalan", lgJalan);
bindLayerToggle("layerPolygon", lgPolygon);

if (el('layerGeoJalan')) {
  el('layerGeoJalan').addEventListener('change', function () {
    if (geoJalanLayer) { this.checked ? geoJalanLayer.addTo(map) : map.removeLayer(geoJalanLayer); }
  });
}
if (el('layerKecamatan')) {
  el('layerKecamatan').addEventListener('change', function () {
    if (geoKecamatanLayer) { this.checked ? geoKecamatanLayer.addTo(map) : map.removeLayer(geoKecamatanLayer); }
  });
}
if (el('layerSungai')) {
  el('layerSungai').addEventListener('change', function () {
    if (geoSungaiLayer) { this.checked ? geoSungaiLayer.addTo(map) : map.removeLayer(geoSungaiLayer); }
  });
}

/* -------------------------------------------------------
   RADIUS SLIDER -> PREVIEW
------------------------------------------------------- */
el('fp_radius').addEventListener('input', function () {
  const r = parseInt(this.value, 10);
  el('fp_radius_text').textContent = r;
  if (previewCircle) previewCircle.setRadius(r);
});

/* -------------------------------------------------------
   MODAL CLOSE BUTTONS
------------------------------------------------------- */
[
  ['closePointModal',       'pointModal'],
  ['cancelPointModal',      'pointModal'],
  ['closeJalanModal',       'jalanModal'],
  ['cancelJalanModal',      'jalanModal'],
  ['closePolygonModal',     'polygonModal'],
  ['cancelPolygonModal',    'polygonModal'],
  ['closefasilitasPublikModal', 'fasilitasPublikModal'],
  ['cancelfasilitasPublikModal','fasilitasPublikModal'],
  ['closePendudukModal',    'pendudukModal'],
  ['cancelPendudukModal',   'pendudukModal'],
].forEach(([btnId, modalId]) => {
  const btn = el(btnId);
  if (btn) btn.addEventListener('click', () => {
    hideModal(modalId);
    clearAllPreview();
  });
});

el('modalBackdrop').addEventListener('click', () => {
  hideAllModals();
  clearAllPreview();
});

/* Konfirmasi hapus */
el('confirmDelete').addEventListener('click', () => {
  if (typeof deleteCallback === 'function') deleteCallback();
  hideModal('deleteModal');
  deleteCallback = null;
});
el('cancelDelete').addEventListener('click', () => {
  hideModal('deleteModal');
  deleteCallback = null;
});

/* -------------------------------------------------------
   SAVE: POINT
------------------------------------------------------- */
el('btnSavePoint').addEventListener('click', () => {
  const nama  = el('point_nama').value.trim();
  const no_wa = el('point_no_wa').value.trim();
  const radio = document.querySelector('input[name="point_buka_24_jam"]:checked');
  const lat   = el('point_latitude').value.trim();
  const lng   = el('point_longitude').value.trim();

  if (!nama || !no_wa || !radio || !lat || !lng) {
    showAlert('Data Tidak Lengkap', 'Peringatan: <b>Semua kolom</b> wajib diisi dan Anda harus <b>mengklik peta</b> untuk menentukan lokasi SPBU terlebih dahulu.');
    return;
  }

  const id  = el('point_id').value;
  const url = id ? 'point/update.php' : 'point/simpan.php';

  const fd = new FormData();
  if (id) fd.append('id', id);
  fd.append('nama', nama);
  fd.append('no_wa', no_wa);
  fd.append('buka_24_jam', radio.value);
  fd.append('latitude', lat);
  fd.append('longitude', lng);

  postData(url, fd).then(res => {
    if (res.status === 'success') {
      if (previewMarker) map.removeLayer(previewMarker);
      
      if (id) {
        const idx = APP_DATA.points.findIndex(x => String(x.id) === String(id));
        if (idx > -1) APP_DATA.points[idx] = res.data;
        lgSpbu24.clearLayers();
        lgSpbuTidak.clearLayers();
        APP_DATA.points.forEach(renderPoint);
      } else {
        APP_DATA.points.push(res.data);
        renderPoint(res.data);
      }
      
      updateDashboardStats();
      if(window.__rebuildCards) window.__rebuildCards();

      hideModal('pointModal');
      showToast(id ? 'Titik berhasil diperbarui.' : 'Titik berhasil disimpan.');
    } else {
      showToast(res.message || 'Gagal menyimpan titik.', 'error');
    }
  });
});

/* -------------------------------------------------------
   SAVE: JALAN
------------------------------------------------------- */
el('btnSaveJalan').addEventListener('click', () => {
  const nama   = el('nama_jalan').value.trim();
  const status = el('status_jalan').value;
  const panjang = el('panjang_meter').value;
  const koordinat = el('koordinat_jalan').value.trim();

  if (!nama || !status || jalanLatLngs.length < 2) { 
    showAlert('Data Tidak Lengkap', 'Peringatan: <b>Nama, status jalan</b> wajib diisi dan Anda harus <b>menggambar garis</b> (minimal 2 titik) di peta.');
    return; 
  }

  const fd = new FormData();
  fd.append('nama_jalan', nama);
  fd.append('status_jalan', status);
  fd.append('panjang_meter', panjang || '0');
  fd.append('koordinat', koordinat);

  postData('jalan/simpan.php', fd).then(res => {
    if (res.status === 'success') {
      clearAllPreview();
      APP_DATA.jalan.push(res.data);
      renderJalan(res.data);
      hideModal('jalanModal');
      el('nama_jalan').value = '';
      el('status_jalan').value = '';
      if(window.__rebuildCards) window.__rebuildCards();
      showToast('Jalan berhasil disimpan.');
    } else {
      showToast(res.message || 'Gagal menyimpan jalan.', 'error');
    }
  });
});

/* -------------------------------------------------------
   SAVE: POLYGON
------------------------------------------------------- */
el('btnSavePolygon').addEventListener('click', () => {
  const nama   = el('nama_parsil').value.trim();
  const status = el('status_kepemilikan').value;
  const luas   = el('luas_tanah').value;
  const koordinat = el('koordinat_polygon').value.trim();

  if (!nama || !status || polygonLatLngs.length < 3) { 
    showAlert('Data Tidak Lengkap', 'Peringatan: <b>Nama, status kepemilikan</b> wajib diisi dan Anda harus <b>menggambar area</b> (minimal 3 titik) di peta.');
    return; 
  }

  const fd = new FormData();
  fd.append('nama_parsil', nama);
  fd.append('status_kepemilikan', status);
  fd.append('luas_tanah', luas || '0');
  fd.append('koordinat', koordinat);

  postData('polygon/simpan.php', fd).then(res => {
    if (res.status === 'success') {
      clearAllPreview();
      APP_DATA.polygons.push(res.data);
      renderPolygon(res.data);
      hideModal('polygonModal');
      el('nama_parsil').value = '';
      el('status_kepemilikan').value = '';
      if(window.__rebuildCards) window.__rebuildCards();
      showToast('Polygon berhasil disimpan.');
    } else {
      showToast(res.message || 'Gagal menyimpan polygon.', 'error');
    }
  });
});

/* -------------------------------------------------------
   SAVE: Fasilitas Publik
------------------------------------------------------- */
el('btnSaveFasilitasPublik').addEventListener('click', () => {
  const nama  = el('fp_nama').value.trim();
  const lat   = el('fp_latitude').value.trim();
  const lng   = el('fp_longitude').value.trim();

  if (!nama || !lat || !lng) { 
    showAlert('Data Tidak Lengkap', 'Peringatan: <b>Semua kolom</b> wajib diisi dan Anda harus <b>mengklik peta</b> untuk menentukan lokasi Fasilitas Publik terlebih dahulu.');
    return; 
  }

  const id  = el('fp_id').value;
  const url = id ? 'fasilitas_publik/update.php' : 'fasilitas_publik/simpan.php';

  const fd = new FormData();
  if (id) fd.append('id', id);
  fd.append('nama',    nama);
  fd.append('jenis',   el('fp_jenis').value);
  fd.append('alamat',  el('fp_alamat').value.trim());
  fd.append('latitude', lat);
  fd.append('longitude', lng);
  fd.append('radius',  el('fp_radius').value);
  fd.append('kontak',  el('fp_kontak').value.trim());

  postData(url, fd).then(res => {
    if (res.status === 'success') {
      if (previewMarker) map.removeLayer(previewMarker);
      if (previewCircle) map.removeLayer(previewCircle);
      previewMarker = null; previewCircle = null;

      // Panggil refreshDataModul secara real-time tanpa reload
      refreshDataModul();

      hideModal('fasilitasPublikModal');
      showToast(id ? 'Fasilitas Publik diperbarui.' : 'Fasilitas Publik berhasil disimpan.');
    } else {
      showToast(res.message || 'Gagal menyimpan.', 'error');
    }
  });
});

/* -------------------------------------------------------
   SAVE: PENDUDUK MISKIN
------------------------------------------------------- */
el('btnSavePenduduk').addEventListener('click', () => {
  const nama = el('pm_nama').value.trim();
  const lat  = el('pm_latitude').value.trim();
  const lng  = el('pm_longitude').value.trim();

  if (!nama || !lat || !lng) { 
    showAlert('Data Tidak Lengkap', 'Peringatan: <b>Semua kolom</b> wajib diisi dan Anda harus <b>mengklik peta</b> untuk menentukan lokasi Penduduk terlebih dahulu.');
    return; 
  }

  const cek = cekJangkauan(parseFloat(lat), parseFloat(lng));
  const id  = el('pm_id').value;
  const url = id ? 'penduduk_miskin/update.php' : 'penduduk_miskin/simpan.php';

  const fd = new FormData();
  if (id) fd.append('id', id);
  fd.append('nama',            nama);
  fd.append('nik',             el('pm_nik').value.trim());
  fd.append('keterangan',      el('pm_keterangan').value.trim());
  fd.append('latitude',        lat);
  fd.append('longitude',       lng);
  fd.append('status_jangkauan', cek.status);
  fd.append('status_bantuan',  el('pm_status_bantuan').value);
  fd.append('fasilitas_publik_id', cek.id || '');
  
  const fileRumah = el('pm_foto_rumah').files[0];
  if (fileRumah) fd.append('foto_rumah', fileRumah);
  const fileKk = el('pm_foto_kk').files[0];
  if (fileKk) fd.append('foto_kk', fileKk);

  postData(url, fd).then(res => {
    if (res.status === 'success') {
      if (previewMarker) { map.removeLayer(previewMarker); previewMarker = null; }

      // Panggil refreshDataModul secara real-time tanpa reload
      refreshDataModul();
      
      hideModal('pendudukModal');
      showToast(id ? 'Data penduduk diperbarui.' : 'Penduduk miskin berhasil disimpan.');
    } else {
      showToast(res.message || 'Gagal menyimpan.', 'error');
    }
  });
});

/* -------------------------------------------------------
   GLOBAL: HAPUS DATA
------------------------------------------------------- */
window.hapusData = function (tipe, id, pesan) {
  showDeleteConfirm(pesan || 'Hapus data ini?', () => {
    const urlMap = {
      point:           'point/hapus.php',
      jalan:           'jalan/hapus.php',
      polygon:         'polygon/hapus.php',
      fasilitas_publik:    'fasilitas_publik/hapus.php',
      penduduk_miskin: 'penduduk_miskin/hapus.php',
    };

    const fd = new FormData();
    fd.append('id', id);

    postData(urlMap[tipe], fd).then(res => {
      if (res.status === 'success') {
        map.closePopup(); // Tutup popup di map
        showToast('Data berhasil dihapus.', 'success');
        if(window.__rebuildCards) setTimeout(() => window.__rebuildCards(), 150);

        // Hapus elemen dari Peta TANPA refresh web
        if (tipe === 'point') {
          const idx = APP_DATA.points.findIndex(x => String(x.id) === String(id));
          if (idx > -1) APP_DATA.points.splice(idx, 1);
          lgSpbu24.clearLayers();
          lgSpbuTidak.clearLayers();
          APP_DATA.points.forEach(renderPoint);
          updateDashboardStats();
        } else if (tipe === 'jalan') {
          const idx = APP_DATA.jalan.findIndex(x => String(x.id) === String(id));
          if (idx > -1) APP_DATA.jalan.splice(idx, 1);
          lgJalan.clearLayers();
          APP_DATA.jalan.forEach(renderJalan);
        } else if (tipe === 'polygon') {
          const idx = APP_DATA.polygons.findIndex(x => String(x.id) === String(id));
          if (idx > -1) APP_DATA.polygons.splice(idx, 1);
          lgPolygon.clearLayers();
          APP_DATA.polygons.forEach(renderPolygon);
        } else if (tipe === 'fasilitas_publik' || tipe === 'penduduk_miskin') {
          // Khusus modul bantuan, panggil refresh penuh
          refreshDataModul();
        }

      } else {
        showToast(res.message || 'Gagal menghapus.', 'error');
      }
    });
  });
};

/* -------------------------------------------------------
   GLOBAL: UPDATE LOKASI DARI DRAG MARKER
------------------------------------------------------- */
window.updateLocation = async function(tipe, id, lat, lng, nama) {
  const urlMap = {
    point: 'point/update_lokasi.php',
    penduduk_miskin: 'penduduk_miskin/update_lokasi.php'
  };

  const fd = new FormData();
  fd.append('id', id);
  fd.append('latitude', lat.toFixed(10));
  fd.append('longitude', lng.toFixed(10));
  
  if (tipe === 'penduduk_miskin') {
    const cek = cekJangkauan(lat, lng);
    fd.append('status_jangkauan', cek.status);
    fd.append('fasilitas_publik_id', cek.id || '');
    
    // Ambil alamat baru
    try {
      const r = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&accept-language=id`);
      const data = await r.json();
      if (data && data.display_name) {
        fd.append('alamat', data.display_name);
      }
    } catch(e) {
      console.warn("Gagal mendapatkan alamat saat drag");
    }
  }

  postData(urlMap[tipe], fd).then(res => {
    if (res.status === 'success') {
      showToast('Lokasi ' + nama + ' berhasil diperbarui.', 'success');
      if (tipe === 'penduduk_miskin') {
        refreshDataModul();
      } else if (tipe === 'point') {
        const idx = APP_DATA.points.findIndex(x => String(x.id) === String(id));
        if (idx > -1) {
            APP_DATA.points[idx].latitude = lat;
            APP_DATA.points[idx].longitude = lng;
        }
      }
    } else {
      showToast('Gagal mengubah lokasi ' + nama, 'error');
      if (tipe === 'penduduk_miskin') refreshDataModul();
    }
  });
};

/* -------------------------------------------------------
   GLOBAL: EDIT Fasilitas Publik
------------------------------------------------------- */
window.editFasilitasPublik = function (id) {
  fetch(`api/get_fasilitas_publik.php?id=${id}`)
    .then(r => r.json())
    .then(res => {
      if (res.status !== 'success') { showToast('Data tidak ditemukan.', 'error'); return; }
      const d = res.data;
      el('fp_id').value       = d.id;
      el('fp_nama').value     = d.nama;
      el('fp_jenis').value    = d.jenis || 'Masjid';
      el('fp_alamat').value   = d.alamat || '';
      el('fp_kontak').value   = d.kontak || '';
      el('fp_latitude').value = d.latitude;
      el('fp_longitude').value= d.longitude;
      el('fp_radius').value   = d.radius;
      el('fp_radius_text').textContent = d.radius;
      el('fpModalTitle').textContent = 'Edit Fasilitas Publik';

      // Preview di peta
      if (previewMarker) map.removeLayer(previewMarker);
      if (previewCircle) map.removeLayer(previewCircle);
      const ll = L.latLng(parseFloat(d.latitude), parseFloat(d.longitude));
      previewMarker = L.marker(ll, { icon: createFPIcon() }).addTo(map);
      previewCircle = L.circle(ll, {
        radius: parseInt(d.radius),
        color: '#e53935', fillColor: '#ef9a9a', fillOpacity: 0.12,
        weight: 2, dashArray: '6 4', interactive: false
      }).addTo(map);
      map.setView(ll, 16);

      map.closePopup();
      showModal('fasilitasPublikModal');
    })
    .catch(() => showToast('Gagal memuat data.', 'error'));
};

/* -------------------------------------------------------
   GLOBAL: EDIT PENDUDUK
------------------------------------------------------- */
window.editPenduduk = function (id) {
  fetch(`api/get_penduduk.php?id=${id}`)
    .then(r => r.json())
    .then(res => {
      if (res.status !== 'success') { showToast('Data tidak ditemukan.', 'error'); return; }
      const d = res.data;
      el('pm_id').value         = d.id;
      el('pm_nama').value       = d.nama;
      el('pm_nik').value        = d.nik || '';
      el('pm_keterangan').value = d.keterangan || '';
      el('pm_status_bantuan').value = d.status_bantuan || 'Belum Disalurkan';
      el('pm_latitude').value   = d.latitude;
      el('pm_longitude').value  = d.longitude;
      el('pmModalTitle').textContent = 'Edit Penduduk Miskin';

      const cek = cekJangkauan(parseFloat(d.latitude), parseFloat(d.longitude));
      updateStatusJangkauan(cek);
      if (previewMarker) map.removeLayer(previewMarker);
      const ll = L.latLng(parseFloat(d.latitude), parseFloat(d.longitude));
      previewMarker = L.marker(ll, {
        icon: createPendudukIcon(cek.status === 'Dalam Jangkauan')
      }).addTo(map);
      map.setView(ll, 16);
      map.closePopup();
      showModal('pendudukModal');
    })
    .catch(() => showToast('Gagal memuat data.', 'error'));
};

/* -------------------------------------------------------
   UTILITY: POST DATA
------------------------------------------------------- */
function postData(url, formData) {
  return fetch(url, { method: 'POST', body: formData })
    .then(r => r.json())
    .catch(err => {
      console.error(err);
      showToast('Terjadi kesalahan koneksi.', 'error');
      return { status: 'error', message: 'Koneksi gagal.' };
    });
}

/* -------------------------------------------------------
   FITUR PENCARIAN (SEARCHING)
------------------------------------------------------- */
const searchInput = el('searchInput');
const searchResults = el('searchResults');

if (searchInput && searchResults) {
  searchInput.addEventListener('input', function() {
    const query = this.value.toLowerCase().trim();
    searchResults.innerHTML = '';
    
    // Minimal ketik 2 huruf baru mencari
    if (query.length < 2) {
      searchResults.classList.add('hidden');
      return;
    }

    let results = [];

    // 1. Cari Titik Biasa
    APP_DATA.points.forEach(item => {
      if (item.nama.toLowerCase().includes(query)) {
        results.push({ title: item.nama, type: '&#x1F4CD; Titik Lokasi', lat: item.latitude, lng: item.longitude });
      }
    });

    // 2. Cari Fasilitas Publik
    fasilitasPublikList.forEach(item => {
      if (item.nama.toLowerCase().includes(query)) {
        results.push({ title: item.nama, type: `&#x1F3E2; Fasilitas Publik (${item.jenis})`, lat: item.latitude, lng: item.longitude });
      }
    });

    // 3. Cari Penduduk Miskin (Berdasarkan Nama atau NIK)
    pendudukList.forEach(p => {
      if (p.data.nama.toLowerCase().includes(query) || (p.data.nik && p.data.nik.includes(query))) {
        results.push({ title: p.data.nama, type: '&#x1F464; Penduduk Miskin', lat: p.data.latitude, lng: p.data.longitude });
      }
    });

    // 4. Cari Jalan
    APP_DATA.jalan.forEach(item => {
      if (item.nama_jalan.toLowerCase().includes(query)) {
        try {
          const feat = JSON.parse(item.koordinat);
          // Ambil titik koordinat pertama dari garis
          const coords = feat.geometry.coordinates[0]; 
          results.push({ title: item.nama_jalan, type: `&#x1F6E3;&#xFE0F; Jalan (${item.status_jalan})`, lat: coords[1], lng: coords[0] });
        } catch(e) {}
      }
    });

    // 5. Cari Polygon
    APP_DATA.polygons.forEach(item => {
      if (item.nama_parsil.toLowerCase().includes(query)) {
        try {
          const feat = JSON.parse(item.koordinat);
          // Ambil titik koordinat pertama dari polygon
          const coords = feat.geometry.coordinates[0][0]; 
          results.push({ title: item.nama_parsil, type: `&#x1F4D0; Polygon (${item.status_kepemilikan})`, lat: coords[1], lng: coords[0] });
        } catch(e) {}
      }
    });

    // Tampilkan Hasil
    if (results.length > 0) {
      results.forEach(res => {
        const div = document.createElement('div');
        div.className = 'search-item';
        div.innerHTML = `
          <span class="search-item-title">${res.title}</span>
          <span class="search-item-type">${res.type}</span>
        `;
        
        // Aksi saat item hasil dicentang
        div.addEventListener('click', () => {
          // Animasi terbang ke lokasi
          map.flyTo([parseFloat(res.lat), parseFloat(res.lng)], 18, { 
            animate: true, 
            duration: 1.5 
          });
          
          searchResults.classList.add('hidden');
          searchInput.value = res.title; // Isi kotak input dengan nama yang dipilih
          
          // Khusus tampilan HP: Sembunyikan sidebar agar peta terlihat langsung
          if (window.innerWidth <= 680) {
            el('sidebar').classList.remove('mobile-open');
          }
        });
        
        searchResults.appendChild(div);
      });
    } else {
      searchResults.innerHTML = '<div class="search-item-empty">Tidak ada data ditemukan</div>';
    }
    
    searchResults.classList.remove('hidden');
  });

  // Menyembunyikan dropdown jika klik di tempat lain
  document.addEventListener('click', (e) => {
    if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {
      searchResults.classList.add('hidden');
    }
  });
}

/* -- Init ------------------------------------------------ */
/* -- Modul Filter & Init -------------------------------- */
function setupModul(modul) {
  const tools = ['btnToolPoint', 'btnToolJalan', 'btnToolPolygon', 'btnToolFasilitasPublik', 'btnToolPenduduk'];
  const layers = ['layerFasilitasPublik', 'layerPendudukDalam', 'layerPendudukLuar', 'layerSpbu24', 'layerSpbuTidak', 'layerJalan', 'layerPolygon', 'layerGeoJalan', 'layerKecamatan', 'layerSungai'];
  
  // Sembunyikan semua kecuali utuh
  if (modul !== 'utuh') {
    tools.forEach(t => { if(el(t)) el(t).style.display = 'none'; });
    layers.forEach(l => { 
      let lgName = '';
      if (l === 'layerSpbu24') lgName = 'lgSpbu24';
      else if (l === 'layerSpbuTidak') lgName = 'lgSpbuTidak';
      else if (l === 'layerPendudukDalam') lgName = 'lgPendudukDalam';
      else if (l === 'layerPendudukLuar') lgName = 'lgPendudukLuar';
      else lgName = l.replace('layer','lg').replace('Geo','geo').replace('Kecamatan','geoKecamatan').replace('Sungai','geoSungai');
      
      try { if(eval(lgName)) map.removeLayer(eval(lgName)); } catch(e){}

      if(el(l)) { 
        el(l).parentElement.style.display = 'none'; 
        el(l).checked = false; 
      } 
    });
  }

  if (modul === 'spbu') {
    if (USER_ROLE !== 'guest') {
      if(el('btnToolPoint')) el('btnToolPoint').style.display = 'inline-flex';
    }
    if(el('layerSpbu24')) { el('layerSpbu24').parentElement.style.display = 'flex'; el('layerSpbu24').checked = true; lgSpbu24.addTo(map); }
    if(el('layerSpbuTidak')) { el('layerSpbuTidak').parentElement.style.display = 'flex'; el('layerSpbuTidak').checked = true; lgSpbuTidak.addTo(map); }
    setMode(USER_ROLE === 'guest' ? 'lokasi' : 'point');
  } else if (modul === 'bantuan') {
    if (USER_ROLE !== 'guest') {
      if(el('btnToolPenduduk')) el('btnToolPenduduk').style.display = 'inline-flex';
      if(el('btnToolFasilitasPublik')) el('btnToolFasilitasPublik').style.display = 'inline-flex';
    }
    if(el('layerFasilitasPublik')) { el('layerFasilitasPublik').parentElement.style.display = 'flex'; el('layerFasilitasPublik').checked = true; lgFasilitasPublik.addTo(map); }
    if(el('layerPendudukDalam')) { el('layerPendudukDalam').parentElement.style.display = 'flex'; el('layerPendudukDalam').checked = true; lgPendudukDalam.addTo(map); }
    if(el('layerPendudukLuar')) { el('layerPendudukLuar').parentElement.style.display = 'flex'; el('layerPendudukLuar').checked = true; lgPendudukLuar.addTo(map); }
    setMode(USER_ROLE === 'guest' ? 'lokasi' : 'penduduk_miskin');
  } else if (modul === 'tematik') {
    if(el('layerGeoJalan')) { el('layerGeoJalan').parentElement.style.display = 'flex'; el('layerGeoJalan').checked = true; if(geoJalanLayer) geoJalanLayer.addTo(map); }
    if(el('layerKecamatan')) { el('layerKecamatan').parentElement.style.display = 'flex'; el('layerKecamatan').checked = true; if(geoKecamatanLayer) geoKecamatanLayer.addTo(map); }
    if(el('layerSungai')) { el('layerSungai').parentElement.style.display = 'flex'; el('layerSungai').checked = true; if(geoSungaiLayer) geoSungaiLayer.addTo(map); }
    setMode('lokasi');
  } else if (modul === 'digitasi') {
    if (USER_ROLE !== 'guest') {
      if(el('btnToolJalan')) el('btnToolJalan').style.display = 'inline-flex';
      if(el('btnToolPolygon')) el('btnToolPolygon').style.display = 'inline-flex';
      if(el('btnToolPoint')) el('btnToolPoint').style.display = 'inline-flex';
    }
    if(el('layerSpbu24')) { el('layerSpbu24').parentElement.style.display = 'flex'; el('layerSpbu24').checked = true; lgSpbu24.addTo(map); }
    if(el('layerSpbuTidak')) { el('layerSpbuTidak').parentElement.style.display = 'flex'; el('layerSpbuTidak').checked = true; lgSpbuTidak.addTo(map); }
    if(el('layerJalan')) { el('layerJalan').parentElement.style.display = 'flex'; el('layerJalan').checked = true; lgJalan.addTo(map); }
    if(el('layerPolygon')) { el('layerPolygon').parentElement.style.display = 'flex'; el('layerPolygon').checked = true; lgPolygon.addTo(map); }
    setMode(USER_ROLE === 'guest' ? 'lokasi' : 'polygon');
  } else { // utuh
    if (typeof USER_ROLE !== 'undefined') {
      if (USER_ROLE === 'guest') setMode('lokasi');
      else if (USER_ROLE === 'petugas') setMode('penduduk_miskin');
      else setMode('point');
    } else {
      setMode('point');
    }
  }

  // Force hide section tools if guest
  if (typeof USER_ROLE !== 'undefined' && USER_ROLE === 'guest' && el('sectionTools')) {
      el('sectionTools').classList.add('hidden');
  }
}

/* -- Alert / Modal Helper -------------------------------- */
window.showAlert = function(title, message) {
  el('alertTitle').textContent = title;
  el('alertMessage').innerHTML = message;
  el('alertModal').classList.remove('hidden');
  el('modalBackdrop').classList.remove('hidden');
};

if(el('btnAlertOk')) {
  el('btnAlertOk').addEventListener('click', () => {
    el('alertModal').classList.add('hidden');
    // Hanya sembunyikan backdrop jika tidak ada modal lain yang terbuka
    if(document.querySelectorAll('.modal:not(.hidden)').length === 0) {
      el('modalBackdrop').classList.add('hidden');
    }
  });
}

// Set mode awal
try {
  setupModul(APP_DATA.modul || 'utuh');
} catch(e) {
  console.error("Error in setupModul:", e);
}

/* ===============================================================
   RIGHT SIDEBAR – PANEL KANAN
   Data List Cards per Modul, flyTo, Search Filter
=============================================================== */

const rightSidebar       = document.getElementById('rightSidebar');
const rightSidebarClose  = document.getElementById('rightSidebarClose');
const rightSidebarToggle = document.getElementById('rightSidebarToggleBtn');
const rightCardList      = document.getElementById('rightCardList');
const rightCardCount     = document.getElementById('rightCardCount');
const rightSearchInput   = document.getElementById('rightSearchInput');

/* ── Marker registry: map from data-id + type → Leaflet marker/layer ── */
const markerRegistry = {};

/* ── Register markers after render ─────────────────────────────── */
// Override renderPoint to register
const _origRenderPoint = renderPoint;
function renderPointAndRegister(item) {
  const mk = _origRenderPoint(item);
  if (mk) markerRegistry['point_' + item.id] = { marker: mk, lat: parseFloat(item.latitude), lng: parseFloat(item.longitude) };
  return mk;
}

/* We need to patch the existing render calls */
/* Re-register all existing data loaded at init */
function registerAllMarkers() {
  /* SPBU / Points */
  lgSpbu24.eachLayer(mk => {
    // match by iterating APP_DATA.points
  });
  /* We'll use a direct lookup approach by storing references during renderPoint */
}

/* ── Right Sidebar Toggle ─────────────────────────────────────── */
let rightOpen = true;

function openRightSidebar() {
  rightSidebar.classList.remove('right-collapsed');
  el('mapContainer').classList.add('with-right-sidebar');
  rightSidebarToggle.classList.add('hidden');
  map.invalidateSize();
  rightOpen = true;
}

function closeRightSidebar() {
  rightSidebar.classList.add('right-collapsed');
  el('mapContainer').classList.remove('with-right-sidebar');
  rightSidebarToggle.classList.remove('hidden');
  map.invalidateSize();
  rightOpen = false;
}

if (rightSidebarClose) rightSidebarClose.addEventListener('click', closeRightSidebar);
if (rightSidebarToggle) rightSidebarToggle.addEventListener('click', openRightSidebar);

// On mobile or tematik: right sidebar starts closed
if (window.innerWidth <= 680 || APP_DATA.modul === 'tematik') {
  closeRightSidebar();
} else {
  openRightSidebar();
}

/* ── Data Card Factory ─────────────────────────────────────────── */

function makeDataCard({ icon, iconClass, name, sub, badge, badgeClass, footerHtml, coords, onClick }) {
  const card = document.createElement('div');
  card.className = 'data-card';

  const hdr = document.createElement('div');
  hdr.className = 'data-card-header';

  const iconWrap = document.createElement('div');
  iconWrap.className = `data-card-icon-wrap ${iconClass}`;
  iconWrap.textContent = icon;

  const body = document.createElement('div');
  body.className = 'data-card-body';

  const nameEl = document.createElement('div');
  nameEl.className = 'data-card-name';
  nameEl.title = name;
  nameEl.textContent = name;

  const subEl = document.createElement('div');
  subEl.className = 'data-card-sub';
  subEl.textContent = sub;

  body.appendChild(nameEl);
  body.appendChild(subEl);

  hdr.appendChild(iconWrap);
  hdr.appendChild(body);

  if (badge) {
    const badgeEl = document.createElement('span');
    badgeEl.className = `data-card-badge ${badgeClass}`;
    badgeEl.textContent = badge;
    hdr.appendChild(badgeEl);
  }

  card.appendChild(hdr);

  if (coords) {
    const coordEl = document.createElement('div');
    coordEl.className = 'data-card-coords';
    coordEl.innerHTML = `<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="10" r="3"/><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/></svg> ${coords}`;
    card.appendChild(coordEl);
  }

  if (footerHtml) {
    const footEl = document.createElement('div');
    footEl.className = 'data-card-footer';
    footEl.innerHTML = footerHtml;
    card.appendChild(footEl);
  }

  card.addEventListener('click', onClick);
  return card;
}

function emptyState(icon, title, sub) {
  const div = document.createElement('div');
  div.className = 'empty-state';
  div.innerHTML = `
    <div class="empty-state-icon">${icon}</div>
    <div class="empty-state-title">${title}</div>
    <div class="empty-state-sub">${sub}</div>
  `;
  return div;
}

function updateCount(count) {
  if (rightCardCount) rightCardCount.textContent = `${count} entri`;
}

/* ── Fly & Open Popup ─────────────────────────────────────────── */
function flyToAndOpenPopup(lat, lng, markerOrLayer) {
  map.flyTo([lat, lng], 17, { animate: true, duration: 1.2 });
  if (markerOrLayer) {
    setTimeout(() => {
      try { markerOrLayer.openPopup(); } catch(e) {}
    }, 1400);
  }
  // On mobile: close right sidebar to see map
  if (window.innerWidth <= 680) closeRightSidebar();
}

/* ── Build Cards by Modul ─────────────────────────────────────── */

/** Find Leaflet marker from a layer group by lat/lng */
function findMarkerInGroup(lg, lat, lng) {
  let found = null;
  lg.eachLayer(mk => {
    if (found) return;
    const ll = mk.getLatLng ? mk.getLatLng() : null;
    if (ll && Math.abs(ll.lat - lat) < 0.0001 && Math.abs(ll.lng - lng) < 0.0001) found = mk;
  });
  return found;
}

function buildCardsSpbu(data, container) {
  if (!data.length) {
    container.appendChild(emptyState('⛽', 'Belum Ada SPBU', 'Tambahkan data SPBU menggunakan alat peta.'));
    return 0;
  }
  data.forEach(item => {
    const lat = parseFloat(item.latitude), lng = parseFloat(item.longitude);
    const is24 = item.buka_24_jam === 'Ya';
    const card = makeDataCard({
      icon: '⛽',
      iconClass: 'dc-icon-spbu',
      name: item.nama,
      sub: `WA: ${item.no_wa || '-'}`,
      badge: is24 ? 'Buka 24 Jam' : 'Tidak 24 Jam',
      badgeClass: is24 ? 'badge-24jam' : 'badge-tidak24',
      coords: `${lat.toFixed(5)}, ${lng.toFixed(5)}`,
      onClick: () => {
        const mk = findMarkerInGroup(is24 ? lgSpbu24 : lgSpbuTidak, lat, lng);
        flyToAndOpenPopup(lat, lng, mk);
      }
    });
    container.appendChild(card);
  });
  return data.length;
}

function buildCardsBantuan(pmData, container) {
  if (!pmData.length) {
    container.appendChild(emptyState('👥', 'Belum Ada Data Penduduk', 'Tambahkan data penduduk miskin menggunakan alat peta.'));
    return 0;
  }
  pmData.forEach(item => {
    const lat = parseFloat(item.data.latitude), lng = parseFloat(item.data.longitude);
    const isDalam = item.data.status_jangkauan === 'Dalam Jangkauan';
    const card = makeDataCard({
      icon: '👤',
      iconClass: 'dc-icon-pm',
      name: item.data.nama,
      sub: `NIK: ${item.data.nik || '-'}`,
      badge: isDalam ? 'Dalam Jangkauan' : 'Luar Jangkauan',
      badgeClass: isDalam ? 'badge-dalam-jk' : 'badge-luar-jk',
      footerHtml: `<div style="display:flex; justify-content:space-between; width:100%; align-items:center;">
        <span style="color:#64748b; font-weight:500;">Status Penyaluran</span>
        <span class="badge-${item.data.status_bantuan === 'Sudah Disalurkan' ? 'sudah' : (item.data.status_bantuan === 'Proses' ? 'proses' : 'belum')}" style="padding:4px 8px; font-size:0.75rem; border-radius:6px; font-weight:700;">${item.data.status_bantuan || 'Belum Disalurkan'}</span>
      </div>`,
      coords: `${lat.toFixed(5)}, ${lng.toFixed(5)}`,
      onClick: () => {
        const mk = findMarkerInGroup(isDalam ? lgPendudukDalam : lgPendudukLuar, lat, lng);
        flyToAndOpenPopup(lat, lng, mk);
      }
    });
    container.appendChild(card);
  });
  return pmData.length;
}

function buildCardsTematik(container) {
  const items = [];

  // Fasilitas Publik
  fasilitasPublikList.forEach(fp => {
    const lat = parseFloat(fp.latitude), lng = parseFloat(fp.longitude);
    items.push({ icon: '🏢', iconClass: 'dc-icon-fp', name: fp.nama, sub: fp.jenis || 'Fasilitas Publik', badge: null, lat, lng, group: lgFasilitasPublik });
  });

  if (!items.length) {
    container.appendChild(emptyState('🗺️', 'Belum Ada Layer', 'Layer tematik (Kecamatan, Sungai, Jalan) belum tersedia.'));
    return 0;
  }

  items.forEach(it => {
    const card = makeDataCard({
      icon: it.icon,
      iconClass: it.iconClass,
      name: it.name,
      sub: it.sub,
      badge: null,
      badgeClass: '',
      coords: `${it.lat.toFixed(5)}, ${it.lng.toFixed(5)}`,
      onClick: () => {
        const mk = findMarkerInGroup(it.group, it.lat, it.lng);
        flyToAndOpenPopup(it.lat, it.lng, mk);
      }
    });
    container.appendChild(card);
  });
  return items.length;
}

function buildCardsDigitasi(jalanData, polygonData, container) {
  let count = 0;

  // Polygons first
  if (polygonData.length) {
    polygonData.forEach(item => {
      const badgeMap = { SHM: 'badge-shm', HGB: 'badge-hgb', HGU: 'badge-hgu', HP: 'badge-hp' };
      let lat = 0, lng = 0;
      try {
        const feat = JSON.parse(item.koordinat);
        const coords = feat.geometry.coordinates[0][0];
        lat = coords[1]; lng = coords[0];
      } catch(e) {}

      const card = makeDataCard({
        icon: '⬜',
        iconClass: 'dc-icon-poly',
        name: item.nama_parsil,
        sub: `Luas: ${parseFloat(item.luas_tanah).toFixed(2)} m²`,
        badge: item.status_kepemilikan,
        badgeClass: badgeMap[item.status_kepemilikan] || 'badge-geo',
        coords: lat ? `${lat.toFixed(5)}, ${lng.toFixed(5)}` : null,
        onClick: () => {
          if (!lat) return;
          const warna = warnaPolygon(item.status_kepemilikan);
          // find polygon in lgPolygon
          let found = null;
          lgPolygon.eachLayer(lyr => {
            if (found) return;
            const c = lyr.getCenter ? lyr.getCenter() : null;
            if (c && Math.abs(c.lat - lat) < 0.002 && Math.abs(c.lng - lng) < 0.002) found = lyr;
          });
          if (lat) map.flyTo([lat, lng], 17, { animate: true, duration: 1.2 });
          if (found) setTimeout(() => { try { found.openPopup(); } catch(e) {} }, 1400);
        }
      });
      container.appendChild(card);
      count++;
    });
  }

  // Jalan
  if (jalanData.length) {
    jalanData.forEach(item => {
      let lat = 0, lng = 0;
      try {
        const feat = JSON.parse(item.koordinat);
        const coords = feat.geometry.coordinates[0];
        lat = coords[1]; lng = coords[0];
      } catch(e) {}

      const statusColors = { 'Jalan Nasional': 'badge-luar-jk', 'Jalan Provinsi': 'badge-hgu', 'Jalan Kabupaten': 'badge-shm' };

      const card = makeDataCard({
        icon: '🛣️',
        iconClass: 'dc-icon-jalan',
        name: item.nama_jalan,
        sub: `${parseFloat(item.panjang_meter).toFixed(0)} m`,
        badge: item.status_jalan,
        badgeClass: statusColors[item.status_jalan] || 'badge-geo',
        coords: lat ? `${lat.toFixed(5)}, ${lng.toFixed(5)}` : null,
        onClick: () => {
          if (!lat) return;
          let found = null;
          lgJalan.eachLayer(lyr => {
            if (found) return;
            const lls = lyr.getLatLngs ? lyr.getLatLngs() : [];
            const first = Array.isArray(lls[0]) ? lls[0][0] : lls[0];
            if (first && Math.abs(first.lat - lat) < 0.001 && Math.abs(first.lng - lng) < 0.001) found = lyr;
          });
          map.flyTo([lat, lng], 16, { animate: true, duration: 1.2 });
          if (found) setTimeout(() => { try { found.openPopup(); } catch(e) {} }, 1400);
          if (window.innerWidth <= 680) closeRightSidebar();
        }
      });
      container.appendChild(card);
      count++;
    });
  }

  if (!count) {
    container.appendChild(emptyState('📐', 'Belum Ada Data Digitasi', 'Tambahkan polygon/jalan menggunakan alat peta.'));
  }
  return count;
}

/* ── Main builder ─────────────────────────────────────────────── */
let currentSearchQuery = '';
let currentUtuhTab     = 'spbu';

function buildRightSidebarCards(modul, searchQ = '') {
  if (!rightCardList) return;
  rightCardList.innerHTML = '';
  let count = 0;

  const filteredPoints = (APP_DATA.points || []).filter(it =>
    !searchQ || (it.nama && it.nama.toLowerCase().includes(searchQ))
  );
  const filteredPM = (pendudukList || []).filter(it =>
    !searchQ || (it.data.nama && it.data.nama.toLowerCase().includes(searchQ)) || (it.data.nik && it.data.nik.includes(searchQ))
  );
  const filteredJalan = (APP_DATA.jalan || []).filter(it =>
    !searchQ || (it.nama_jalan && it.nama_jalan.toLowerCase().includes(searchQ))
  );
  const filteredPolygon = (APP_DATA.polygons || []).filter(it =>
    !searchQ || (it.nama_parsil && it.nama_parsil.toLowerCase().includes(searchQ))
  );
  const filteredFP = (fasilitasPublikList || []).filter(it =>
    !searchQ || (it.nama && it.nama.toLowerCase().includes(searchQ))
  );

  if (modul === 'spbu') {
    count = buildCardsSpbu(filteredPoints, rightCardList);
  } else if (modul === 'bantuan') {
    count = buildCardsBantuan(filteredPM, rightCardList);
    // Also add FP
    if (filteredFP.length) {
      filteredFP.forEach(fp => {
        const lat = parseFloat(fp.latitude), lng = parseFloat(fp.longitude);
        const card = makeDataCard({
          icon: '🏢', iconClass: 'dc-icon-fp',
          name: fp.nama, sub: fp.jenis || 'Fasilitas Publik',
          badge: null, badgeClass: '',
          coords: `${lat.toFixed(5)}, ${lng.toFixed(5)}`,
          onClick: () => {
            const mk = findMarkerInGroup(lgFasilitasPublik, lat, lng);
            flyToAndOpenPopup(lat, lng, mk);
          }
        });
        rightCardList.appendChild(card);
        count++;
      });
    }
  } else if (modul === 'tematik') {
    // Kosongkan daftar data untuk peta tematik
    rightCardList.appendChild(emptyState('🗺️', 'Peta Tematik', 'Mode Peta Tematik hanya menampilkan layer poligon dan garis pada peta.'));
    count = 0;
  } else if (modul === 'digitasi') {
    count = buildCardsDigitasi(filteredJalan, filteredPolygon, rightCardList);
  } else { // utuh – use tab system
    if (currentUtuhTab === 'spbu') count = buildCardsSpbu(filteredPoints, rightCardList);
    else if (currentUtuhTab === 'bantuan') count = buildCardsBantuan(filteredPM, rightCardList);
    else if (currentUtuhTab === 'jalan') {
      if (!filteredJalan.length) {
        rightCardList.appendChild(emptyState('🛣️', 'Belum Ada Jalan', 'Tambahkan data jalan menggunakan alat peta.'));
      } else {
        filteredJalan.forEach(item => {
          let lat = 0, lng = 0;
          try { const f = JSON.parse(item.koordinat); lat = f.geometry.coordinates[0][1]; lng = f.geometry.coordinates[0][0]; } catch(e) {}
          const card = makeDataCard({
            icon: '🛣️', iconClass: 'dc-icon-jalan',
            name: item.nama_jalan, sub: `${parseFloat(item.panjang_meter).toFixed(0)} m · ${item.status_jalan}`,
            badge: null, badgeClass: '',
            coords: lat ? `${lat.toFixed(5)}, ${lng.toFixed(5)}` : null,
            onClick: () => { if (lat) map.flyTo([lat, lng], 16, { animate: true, duration: 1.2 }); if (window.innerWidth <= 680) closeRightSidebar(); }
          });
          rightCardList.appendChild(card);
          count++;
        });
      }
    } else if (currentUtuhTab === 'polygon') {
      if (!filteredPolygon.length) {
        rightCardList.appendChild(emptyState('⬜', 'Belum Ada Parsil', 'Tambahkan polygon menggunakan alat peta.'));
      } else {
        const badgeMap = { SHM: 'badge-shm', HGB: 'badge-hgb', HGU: 'badge-hgu', HP: 'badge-hp' };
        filteredPolygon.forEach(item => {
          let lat = 0, lng = 0;
          try { const f = JSON.parse(item.koordinat); lat = f.geometry.coordinates[0][0][1]; lng = f.geometry.coordinates[0][0][0]; } catch(e) {}
          const card = makeDataCard({
            icon: '⬜', iconClass: 'dc-icon-poly',
            name: item.nama_parsil, sub: `Luas: ${parseFloat(item.luas_tanah).toFixed(2)} m²`,
            badge: item.status_kepemilikan, badgeClass: badgeMap[item.status_kepemilikan] || 'badge-geo',
            coords: lat ? `${lat.toFixed(5)}, ${lng.toFixed(5)}` : null,
            onClick: () => {
              if (lat) {
                map.flyTo([lat, lng], 17, { animate: true, duration: 1.2 });
                let found = null;
                lgPolygon.eachLayer(lyr => {
                  if (found) return;
                  const c = lyr.getCenter ? lyr.getCenter() : null;
                  if (c && Math.abs(c.lat - lat) < 0.002 && Math.abs(c.lng - lng) < 0.002) found = lyr;
                });
                if (found) setTimeout(() => { try { found.openPopup(); } catch(e) {} }, 1400);
              }
              if (window.innerWidth <= 680) closeRightSidebar();
            }
          });
          rightCardList.appendChild(card);
          count++;
        });
      }
    }
  }

  updateCount(count);
}

/* ── Tab Switching (Modul Utuh) ───────────────────────────────── */
const tabBtns = document.querySelectorAll('.right-tab-btn');
tabBtns.forEach(btn => {
  btn.addEventListener('click', () => {
    tabBtns.forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
    currentUtuhTab = btn.dataset.tab;
    buildRightSidebarCards(APP_DATA.modul, currentSearchQuery);
  });
});

/* ── Right Search Input ───────────────────────────────────────── */
if (rightSearchInput) {
  let rsTimer = null;
  rightSearchInput.addEventListener('input', function() {
    clearTimeout(rsTimer);
    const q = this.value.toLowerCase().trim();
    rsTimer = setTimeout(() => {
      currentSearchQuery = q;
      buildRightSidebarCards(APP_DATA.modul, q);
    }, 200);
  });
}

/* ── Trigger initial card build after markers loaded ────────────── */
// We wait a tick to let renderPoint/renderPenduduk etc. complete
setTimeout(() => buildRightSidebarCards(APP_DATA.modul), 100);

/* ── Re-build after CRUD ops ─────────────────────────────────── */
// Patch postData success to rebuild cards
const _origPostData = window.postData;
// We override the save success moments via a custom event
document.addEventListener('webgis:dataChanged', () => {
  buildRightSidebarCards(APP_DATA.modul, currentSearchQuery);
});

// Hook into showToast to trigger rebuild on success saves
const _origShowToast = showToast;
// We'll re-export showToast patch at module level
window.__rebuildCards = () => buildRightSidebarCards(APP_DATA.modul, currentSearchQuery);

/* ===============================================================
   CHART.JS MODAL
=============================================================== */

let activeChart = null;

const chartModal    = document.getElementById('chartModal');
const chartModalClose = document.getElementById('chartModalClose');
const chartModalBody  = document.getElementById('chartModalBody');
const chartModalTitle = document.getElementById('chartModalTitle');
const chartModalSub   = document.getElementById('chartModalSubtitle');
const chartModalIcon  = document.getElementById('chartModalIcon');
const btnStatistik    = document.getElementById('btnLihatStatistik');

// Chart color palette (Merah Putih premium)
const CHART_COLORS = {
  red:      'rgba(225, 29, 72, 0.85)',
  redLight: 'rgba(225, 29, 72, 0.18)',
  redMid:   'rgba(251, 113, 133, 0.85)',
  dark:     'rgba(15, 23, 42, 0.85)',
  darkMid:  'rgba(71, 85, 105, 0.7)',
  green:    'rgba(22, 163, 74, 0.85)',
  greenLight:'rgba(22,163,74,0.18)',
  blue:     'rgba(59, 130, 246, 0.85)',
  amber:    'rgba(217, 119, 6, 0.85)',
  purple:   'rgba(107, 33, 168, 0.85)',
  teal:     'rgba(20, 184, 166, 0.85)',
};

const CHART_DEFAULTS = {
  responsive: true,
  maintainAspectRatio: true,
  plugins: {
    legend: {
      position: 'bottom',
      labels: {
        font: { family: "'Plus Jakarta Sans', sans-serif", size: 12, weight: '600' },
        padding: 16,
        usePointStyle: true,
        pointStyleWidth: 10,
        color: '#334155'
      }
    },
    tooltip: {
      backgroundColor: 'rgba(15,23,42,0.9)',
      titleColor: '#f8fafc',
      bodyColor: '#cbd5e1',
      borderColor: 'rgba(225,29,72,0.3)',
      borderWidth: 1,
      cornerRadius: 10,
      padding: 12,
      titleFont: { family: "'Plus Jakarta Sans', sans-serif", weight: '800', size: 13 },
      bodyFont: { family: "'Plus Jakarta Sans', sans-serif", weight: '500', size: 12 },
    }
  }
};

function destroyChart() {
  if (activeChart) { activeChart.destroy(); activeChart = null; }
}

function openChartModal() {
  if (!chartModal) return;
  destroyChart();
  chartModalBody.innerHTML = '';

  const modul = APP_DATA.modul;

  if (modul === 'spbu') {
    chartModalIcon.textContent = '⛽';
    chartModalTitle.textContent = 'Statistik SPBU';
    chartModalSub.textContent  = 'Distribusi SPBU berdasarkan jam operasional';
    buildChartSpbu();
  } else if (modul === 'bantuan') {
    chartModalIcon.textContent = '👥';
    chartModalTitle.textContent = 'Statistik Bantuan';
    chartModalSub.textContent  = 'Cakupan jangkauan penduduk miskin';
    buildChartBantuan();
  } else if (modul === 'tematik') {
    chartModalIcon.textContent = '🗺️';
    chartModalTitle.textContent = 'Statistik Tematik';
    chartModalSub.textContent  = 'Distribusi jaringan jalan berdasarkan status';
    buildChartTematik();
  } else if (modul === 'digitasi') {
    chartModalIcon.textContent = '📐';
    chartModalTitle.textContent = 'Statistik Digitasi';
    chartModalSub.textContent  = 'Proporsi kepemilikan tanah & panjang jalan';
    buildChartDigitasi();
  } else {
    chartModalIcon.textContent = '📊';
    chartModalTitle.textContent = 'Dashboard Statistik';
    chartModalSub.textContent  = 'Ringkasan semua modul data spasial';
    buildChartUtuh();
  }

  chartModal.classList.remove('hidden');
}

function closeChartModal() {
  chartModal.classList.add('hidden');
  destroyChart();
}

if (btnStatistik) btnStatistik.addEventListener('click', openChartModal);
if (chartModalClose) chartModalClose.addEventListener('click', closeChartModal);
if (chartModal) chartModal.addEventListener('click', e => { if (e.target === chartModal) closeChartModal(); });

document.addEventListener('keydown', e => {
  if (e.key === 'Escape') closeChartModal();
});

/* ── Chart Builders per Modul ─────────────────────────────────── */

function statMiniHTML(val, label, color) {
  return `<div class="chart-stat-mini" style="border-left:3px solid ${color}">
    <div class="chart-stat-mini-val" style="color:${color}">${val}</div>
    <div class="chart-stat-mini-label">${label}</div>
  </div>`;
}

function buildChartSpbu() {
  const total  = APP_DATA.points.length;
  const ya     = APP_DATA.points.filter(p => p.buka_24_jam === 'Ya').length;
  const tidak  = total - ya;

  chartModalBody.innerHTML = `
    <div class="chart-stat-row">
      ${statMiniHTML(total, 'Total SPBU', '#0f172a')}
      ${statMiniHTML(ya,    'Buka 24 Jam', CHART_COLORS.green.replace('0.85','1'))}
      ${statMiniHTML(tidak, 'Tidak 24 Jam', CHART_COLORS.red.replace('0.85','1'))}
    </div>
    <div class="chart-canvas-wrap" style="max-width:360px;margin:0 auto;">
      <canvas id="chartCanvas" height="300"></canvas>
    </div>`;

  const ctx = document.getElementById('chartCanvas').getContext('2d');
  activeChart = new Chart(ctx, {
    type: 'doughnut',
    data: {
      labels: ['Buka 24 Jam', 'Tidak 24 Jam'],
      datasets: [{
        data: [ya, tidak],
        backgroundColor: [CHART_COLORS.green, CHART_COLORS.red],
        borderColor: ['#fff', '#fff'],
        borderWidth: 3,
        hoverBorderWidth: 4,
        hoverOffset: 8
      }]
    },
    options: {
      ...CHART_DEFAULTS,
      cutout: '65%',
      plugins: {
        ...CHART_DEFAULTS.plugins,
        legend: { ...CHART_DEFAULTS.plugins.legend, position: 'bottom' }
      }
    }
  });
}

function buildChartBantuan() {
  const totalPM   = pendudukList.length;
  const dalam     = pendudukList.filter(p => {
    const cek = cekJangkauan(parseFloat(p.data.latitude), parseFloat(p.data.longitude));
    return cek.status === 'Dalam Jangkauan';
  }).length;
  const luar      = totalPM - dalam;
  const totalFP   = fasilitasPublikList.length;
  const persen    = totalPM > 0 ? ((dalam / totalPM) * 100).toFixed(1) : 0;

  chartModalBody.innerHTML = `
    <div class="chart-stat-row">
      ${statMiniHTML(totalFP, 'Fasilitas Publik', '#3b82f6')}
      ${statMiniHTML(totalPM, 'Penduduk Miskin', '#0f172a')}
      ${statMiniHTML(dalam,   'Terjangkau', '#16a34a')}
      ${statMiniHTML(luar,    'Luar Jangkauan', '#e11d48')}
      ${statMiniHTML(persen + '%', 'Cakupan', '#d97706')}
    </div>
    <div class="chart-canvas-wrap" style="max-width:420px;margin:0 auto;">
      <canvas id="chartCanvas" height="260"></canvas>
    </div>`;

  const ctx = document.getElementById('chartCanvas').getContext('2d');
  activeChart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Dalam Jangkauan', 'Luar Jangkauan'],
      datasets: [{
        label: 'Jumlah Penduduk',
        data: [dalam, luar],
        backgroundColor: [CHART_COLORS.green, CHART_COLORS.red],
        borderRadius: 8,
        borderSkipped: false,
        maxBarThickness: 80
      }]
    },
    options: {
      ...CHART_DEFAULTS,
      scales: {
        y: {
          beginAtZero: true,
          grid: { color: 'rgba(0,0,0,0.06)' },
          ticks: { font: { family: "'Plus Jakarta Sans', sans-serif", weight: '600', size: 11 }, color: '#64748b' }
        },
        x: {
          grid: { display: false },
          ticks: { font: { family: "'Plus Jakarta Sans', sans-serif", weight: '700', size: 12 }, color: '#0f172a' }
        }
      },
      plugins: { ...CHART_DEFAULTS.plugins, legend: { display: false } }
    }
  });
}

function buildChartTematik() {
  // Count jalan by status from APP_DATA.jalan
  const counts = { 'Jalan Nasional': 0, 'Jalan Provinsi': 0, 'Jalan Kabupaten': 0 };
  const panjang = { 'Jalan Nasional': 0, 'Jalan Provinsi': 0, 'Jalan Kabupaten': 0 };
  (APP_DATA.jalan || []).forEach(j => {
    if (counts[j.status_jalan] !== undefined) {
      counts[j.status_jalan]++;
      panjang[j.status_jalan] += parseFloat(j.panjang_meter) || 0;
    }
  });

  const totalPanjang = Object.values(panjang).reduce((a,b) => a+b, 0);

  chartModalBody.innerHTML = `
    <div class="chart-stat-row">
      ${statMiniHTML(counts['Jalan Nasional'],  'Nasional',  '#d32f2f')}
      ${statMiniHTML(counts['Jalan Provinsi'],  'Provinsi',  '#f57c00')}
      ${statMiniHTML(counts['Jalan Kabupaten'], 'Kabupaten', '#388e3c')}
      ${statMiniHTML((totalPanjang/1000).toFixed(2)+' km', 'Total Panjang', '#0f172a')}
    </div>
    <div class="chart-canvas-wrap" style="max-width:460px;margin:0 auto;">
      <canvas id="chartCanvas" height="240"></canvas>
    </div>`;

  const ctx = document.getElementById('chartCanvas').getContext('2d');
  activeChart = new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten'],
      datasets: [{
        label: 'Panjang (m)',
        data: [panjang['Jalan Nasional'], panjang['Jalan Provinsi'], panjang['Jalan Kabupaten']],
        backgroundColor: ['rgba(211,47,47,0.85)', 'rgba(245,124,0,0.85)', 'rgba(56,142,60,0.85)'],
        borderRadius: 8,
        borderSkipped: false,
        maxBarThickness: 80
      }]
    },
    options: {
      ...CHART_DEFAULTS,
      scales: {
        y: {
          beginAtZero: true,
          grid: { color: 'rgba(0,0,0,0.06)' },
          ticks: {
            font: { family: "'Plus Jakarta Sans', sans-serif", weight: '600', size: 11 },
            color: '#64748b',
            callback: val => val >= 1000 ? (val/1000).toFixed(1)+'km' : val+'m'
          }
        },
        x: {
          grid: { display: false },
          ticks: { font: { family: "'Plus Jakarta Sans', sans-serif", weight: '700', size: 11 }, color: '#0f172a' }
        }
      },
      plugins: { ...CHART_DEFAULTS.plugins, legend: { display: false } }
    }
  });
}

function buildChartDigitasi() {
  const kepMap = { SHM: 0, HGB: 0, HGU: 0, HP: 0 };
  (APP_DATA.polygons || []).forEach(p => { if (kepMap[p.status_kepemilikan] !== undefined) kepMap[p.status_kepemilikan]++; });

  const totalPoly  = APP_DATA.polygons.length;
  const totalJalan = APP_DATA.jalan.length;

  chartModalBody.innerHTML = `
    <div class="chart-stat-row">
      ${statMiniHTML(totalPoly,  'Total Parsil', '#0f172a')}
      ${statMiniHTML(kepMap.SHM, 'SHM', '#166534')}
      ${statMiniHTML(kepMap.HGB, 'HGB', '#1e40af')}
      ${statMiniHTML(kepMap.HGU, 'HGU', '#854d0e')}
      ${statMiniHTML(kepMap.HP,  'HP',  '#6b21a8')}
      ${statMiniHTML(totalJalan, 'Ruas Jalan', '#d32f2f')}
    </div>
    <div class="chart-canvas-wrap" style="max-width:340px;margin:0 auto;">
      <canvas id="chartCanvas" height="300"></canvas>
    </div>`;

  const ctx = document.getElementById('chartCanvas').getContext('2d');
  activeChart = new Chart(ctx, {
    type: 'polarArea',
    data: {
      labels: ['SHM', 'HGB', 'HGU', 'HP'],
      datasets: [{
        data: [kepMap.SHM, kepMap.HGB, kepMap.HGU, kepMap.HP],
        backgroundColor: [
          'rgba(22,163,74,0.75)',
          'rgba(59,130,246,0.75)',
          'rgba(217,119,6,0.75)',
          'rgba(107,33,168,0.75)'
        ],
        borderColor: '#fff',
        borderWidth: 2
      }]
    },
    options: {
      ...CHART_DEFAULTS,
      scales: {
        r: {
          grid: { color: 'rgba(0,0,0,0.08)' },
          ticks: {
            backdropColor: 'transparent',
            font: { family: "'Plus Jakarta Sans', sans-serif", size: 10 },
            color: '#64748b'
          }
        }
      }
    }
  });
}

function buildChartUtuh() {
  const totalSPBU = APP_DATA.points.length;
  const spbu24    = APP_DATA.points.filter(p => p.buka_24_jam === 'Ya').length;
  const totalPM   = pendudukList.length;
  const dalam     = pendudukList.filter(p => cekJangkauan(parseFloat(p.data.latitude), parseFloat(p.data.longitude)).status === 'Dalam Jangkauan').length;
  const totalJalan   = APP_DATA.jalan.length;
  const totalPolygon = APP_DATA.polygons.length;
  const totalFP      = fasilitasPublikList.length;

  chartModalBody.innerHTML = `
    <div class="chart-stat-row">
      ${statMiniHTML(totalSPBU,   'Total SPBU', '#0f172a')}
      ${statMiniHTML(totalPM,     'Penduduk Miskin', '#e11d48')}
      ${statMiniHTML(totalFP,     'Fasilitas Publik', '#3b82f6')}
      ${statMiniHTML(totalJalan,  'Ruas Jalan', '#d32f2f')}
      ${statMiniHTML(totalPolygon,'Parsil Tanah', '#6b21a8')}
    </div>
    <div class="chart-dashboard-grid" style="margin-top:4px;">
      <div class="chart-mini-card">
        <div class="chart-mini-title">⛽ SPBU</div>
        <canvas id="chartSpbu" height="180"></canvas>
      </div>
      <div class="chart-mini-card">
        <div class="chart-mini-title">👥 Jangkauan Bantuan</div>
        <canvas id="chartBantuan" height="180"></canvas>
      </div>
    </div>`;

  const ctxS = document.getElementById('chartSpbu').getContext('2d');
  new Chart(ctxS, {
    type: 'doughnut',
    data: {
      labels: ['Buka 24 Jam', 'Tidak 24 Jam'],
      datasets: [{ data: [spbu24, totalSPBU - spbu24], backgroundColor: [CHART_COLORS.green, CHART_COLORS.red], borderColor: '#fff', borderWidth: 2, hoverOffset: 6 }]
    },
    options: { ...CHART_DEFAULTS, cutout: '60%', plugins: { ...CHART_DEFAULTS.plugins, legend: { ...CHART_DEFAULTS.plugins.legend, labels: { ...CHART_DEFAULTS.plugins.legend.labels, font: { family: "'Plus Jakarta Sans', sans-serif", size: 10, weight: '600' }, padding: 10 } } } }
  });

  const ctxB = document.getElementById('chartBantuan').getContext('2d');
  new Chart(ctxB, {
    type: 'doughnut',
    data: {
      labels: ['Terjangkau', 'Luar Jangkauan'],
      datasets: [{ data: [dalam, totalPM - dalam], backgroundColor: [CHART_COLORS.green, CHART_COLORS.red], borderColor: '#fff', borderWidth: 2, hoverOffset: 6 }]
    },
    options: { ...CHART_DEFAULTS, cutout: '60%', plugins: { ...CHART_DEFAULTS.plugins, legend: { ...CHART_DEFAULTS.plugins.legend, labels: { ...CHART_DEFAULTS.plugins.legend.labels, font: { family: "'Plus Jakarta Sans', sans-serif", size: 10, weight: '600' }, padding: 10 } } } }
  });
}

/* ============================================================
   MANAJEMEN DATA PENDUDUK (MODUL BANTUAN)
============================================================ */
window.openManajemenModal = function() {
  document.getElementById('manajemenModal').classList.remove('hidden');
  document.getElementById('modalBackdrop').classList.remove('hidden');
  renderTabelManajemen('Semua');
  
  // Set tab aktif kembali ke 'Semua'
  document.querySelectorAll('.mj-tab').forEach(t => t.classList.remove('active'));
  const allTab = document.querySelector('.mj-tab[data-filter="Semua"]');
  if(allTab) allTab.classList.add('active');
};

if (document.getElementById('closeManajemenModal')) {
  document.getElementById('closeManajemenModal').addEventListener('click', () => {
    document.getElementById('manajemenModal').classList.add('hidden');
    // Cek apakah modal lain tidak terbuka sebelum menutup backdrop
    if(document.querySelectorAll('.modal:not(.hidden)').length <= 1) {
      document.getElementById('modalBackdrop').classList.add('hidden');
    }
  });
}

document.querySelectorAll('.mj-tab').forEach(tab => {
  tab.addEventListener('click', (e) => {
    document.querySelectorAll('.mj-tab').forEach(t => t.classList.remove('active'));
    e.target.classList.add('active');
    renderTabelManajemen(e.target.getAttribute('data-filter'));
  });
});

window.renderTabelManajemen = function(filter) {
  const tbody = document.getElementById('manajemenTableBody');
  if (!tbody) return;
  tbody.innerHTML = '';

  let no = 1;
  pendudukList.forEach(item => {
    const d = item.data;
    const statusBantuan = d.status_bantuan || 'Belum Disalurkan';
    
    if (filter !== 'Semua' && statusBantuan !== filter) return;

    let badgeClass = 'belum';
    if (statusBantuan === 'Proses') badgeClass = 'proses';
    if (statusBantuan === 'Sudah Disalurkan') badgeClass = 'sudah';

    let jangkauanColor = d.status_jangkauan === 'Dalam Jangkauan' ? '#16a34a' : '#e11d48';

    const tr = document.createElement('tr');
    tr.innerHTML = `
      <td style="font-weight:600;">${no++}</td>
      <td>
        <div style="font-weight:700; color:#1e293b;">${d.nama}</div>
        <div style="font-size:0.75rem; color:#64748b;">NIK: ${d.nik || '-'}</div>
      </td>
      <td>
        <span style="font-weight:700; color:${jangkauanColor}; padding:4px 8px; background:${jangkauanColor}1a; border-radius:6px; display:inline-block;">
          ${d.status_jangkauan}
        </span>
      </td>
      <td>
        ${d.foto_rumah ? `<a href="javascript:void(0)" onclick="lihatFotoModal('uploads/${d.foto_rumah}')" style="color:#2563eb; text-decoration:none; font-weight:600;">Lihat Foto</a>` : '<span style="color:#94a3b8;">-</span>'}
      </td>
      <td>
        <div class="mj-dropdown" id="dropdown-${d.id}">
          <div class="mj-dropdown-toggle ${badgeClass}" onclick="toggleDropdown(${d.id})">
            ${statusBantuan} <span class="caret">▼</span>
          </div>
          <div class="mj-dropdown-menu">
            <div class="mj-dropdown-item belum" onclick="updateStatusLangsung(${d.id}, 'Belum Disalurkan', '${statusBantuan}')">Belum Disalurkan</div>
            <div class="mj-dropdown-item proses" onclick="updateStatusLangsung(${d.id}, 'Proses', '${statusBantuan}')">Proses</div>
            <div class="mj-dropdown-item sudah" onclick="updateStatusLangsung(${d.id}, 'Sudah Disalurkan', '${statusBantuan}')">Sudah Disalurkan</div>
          </div>
        </div>
      </td>
    `;
    tbody.appendChild(tr);
  });
  
  if (no === 1) {
    tbody.innerHTML = `<tr><td colspan="5" style="text-align:center; padding: 20px; color:#64748b;">Tidak ada data.</td></tr>`;
  }
};

window.lihatFotoModal = function(url) {
  if (typeof Swal !== 'undefined') {
    Swal.fire({
      imageUrl: url,
      imageAlt: 'Foto',
      showConfirmButton: false,
      showCloseButton: true,
      customClass: { popup: 'swal-foto-popup' }
    });
  } else {
    window.open(url, '_blank');
  }
};

window.updateStatusLangsung = function(id, newValue, oldValue) {
  // Tutup dropdown global
  if (typeof closeGlobalDropdown === 'function') closeGlobalDropdown();

  if (newValue === oldValue) return;
  
  const fd = new FormData();
  fd.append('id', id);
  fd.append('status_bantuan', newValue);

  fetch('api/update_status_bantuan.php', { method: 'POST', body: fd })
    .then(r => r.json())
    .then(res => {
      if (res.status === 'success') {
        showToast('Status penyaluran diperbarui.', 'success');
        refreshDataModul().then(() => {
          const activeFilter = document.querySelector('.mj-tab.active').getAttribute('data-filter');
          renderTabelManajemen(activeFilter);
        });
      } else {
        showToast('Gagal mengubah status', 'error');
        const activeFilter = document.querySelector('.mj-tab.active').getAttribute('data-filter');
        renderTabelManajemen(activeFilter);
      }
    }).catch(err => {
      showToast('Koneksi terputus', 'error');
      const activeFilter = document.querySelector('.mj-tab.active').getAttribute('data-filter');
      renderTabelManajemen(activeFilter);
    });
};

let globalDropdown = null;

window.closeGlobalDropdown = function() {
  if (globalDropdown) {
    globalDropdown.remove();
    globalDropdown = null;
  }
  document.querySelectorAll('.mj-dropdown.open').forEach(d => d.classList.remove('open'));
};

window.toggleDropdown = function(id) {
  const el = document.getElementById(`dropdown-${id}`);
  if (!el) return;
  
  // If clicking the same one that's open, close it
  if (el.classList.contains('open')) {
    closeGlobalDropdown();
    return;
  }
  
  // Close any existing first
  closeGlobalDropdown();
  
  // Open it
  el.classList.add('open');
  
  // Create a new one on body
  const menuTemplate = el.querySelector('.mj-dropdown-menu');
  
  globalDropdown = document.createElement('div');
  globalDropdown.className = 'mj-dropdown-menu';
  globalDropdown.innerHTML = menuTemplate.innerHTML;
  
  const rect = el.querySelector('.mj-dropdown-toggle').getBoundingClientRect();
  const spaceBelow = window.innerHeight - rect.bottom;
  
  globalDropdown.style.position = 'fixed';
  globalDropdown.style.left = rect.left + 'px';
  globalDropdown.style.zIndex = '9999999';
  
  // Force visibility since it's not under .mj-dropdown.open anymore
  globalDropdown.style.opacity = '1';
  globalDropdown.style.visibility = 'visible';
  globalDropdown.style.transform = 'scaleY(1)';
  
  if (spaceBelow < 140) {
    globalDropdown.style.top = 'auto';
    globalDropdown.style.bottom = (window.innerHeight - rect.top + 6) + 'px';
    globalDropdown.style.transformOrigin = 'bottom left';
  } else {
    globalDropdown.style.top = (rect.bottom + 6) + 'px';
    globalDropdown.style.bottom = 'auto';
    globalDropdown.style.transformOrigin = 'top left';
  }
  
  document.body.appendChild(globalDropdown);
};

// Global click to close
document.addEventListener('click', function(e) {
  if (!e.target.closest('.mj-dropdown') && !e.target.closest('.mj-dropdown-menu')) {
    closeGlobalDropdown();
  }
});

// Close when scrolling table to prevent floating menu out of sync
document.querySelector('#manajemenModal .table-responsive')?.addEventListener('scroll', closeGlobalDropdown);
window.addEventListener('scroll', closeGlobalDropdown, true);

})();

