// Regional Map — sebaran responden di peta Indonesia.
//
// Pakai Leaflet (CDN-loaded di index.html) dengan OSM tiles. Kecamatan-level
// detail tersedia otomatis saat user zoom in karena OSM punya full coverage
// Indonesia. Lat/lon di-collect dari mobile-flow saat responden klik
// "Auto-detect GPS" di pertanyaan tipe location.
//
// Filter:
//   • Date range: 7d / 30d / 90d / all
//   • Campaign: dropdown semua campaign di workspace
//
// Side panel kanan: list region (text) + count, ranked.

const { useState: useState_rm, useEffect: useEffect_rm, useRef: useRef_rm } = React;

const INDONESIA_CENTER = [-2.5, 118]; // around Sulawesi
const INDONESIA_ZOOM = 5;

const RANGE_OPTIONS = [
  { id: '7d',  label: '7 hari',   ms: 7  * 86400000 },
  { id: '30d', label: '30 hari',  ms: 30 * 86400000 },
  { id: '90d', label: '90 hari',  ms: 90 * 86400000 },
  { id: 'all', label: 'Semua',    ms: null },
];

function RegionalMap() {
  const mapEl = useRef_rm(null);
  const mapRef = useRef_rm(null);
  const clusterRef = useRef_rm(null);

  const [campaigns, setCampaigns] = useState_rm([]);
  const [campaignId, setCampaignId] = useState_rm('all');
  const [range, setRange] = useState_rm('30d');
  const [provinceFilter, setProvinceFilter] = useState_rm('');
  const [kotakabFilter, setKotakabFilter] = useState_rm('');
  const [responses, setResponses] = useState_rm([]);
  const [loading, setLoading] = useState_rm(true);

  // Daftar kotakab yang muncul di dropdown — narrows kalau provinsi sudah dipilih.
  const kotakabOptions = provinceFilter
    ? (window.kotakabsInProvince ? window.kotakabsInProvince(provinceFilter) : [])
    : [];

  // Bersihkan kotakab kalau provinsi diganti & kotakab existing tidak ada di provinsi baru.
  useEffect_rm(() => {
    if (kotakabFilter && !kotakabOptions.includes(kotakabFilter)) {
      setKotakabFilter('');
    }
  }, [provinceFilter]); // eslint-disable-line react-hooks/exhaustive-deps

  // Load campaigns + their responses in parallel.
  useEffect_rm(() => {
    window.api.listCampaigns()
      .then((r) => setCampaigns(r.campaigns || []))
      .catch(() => setCampaigns([]));
  }, []);

  useEffect_rm(() => {
    setLoading(true);
    const target = campaignId === 'all'
      ? campaigns.map((c) => c.id)
      : [campaignId].filter(Boolean);
    if (target.length === 0) {
      setResponses([]);
      setLoading(false);
      return;
    }
    Promise.all(
      target.map((id) => window.api.listResponses(id, 500).catch(() => ({ responses: [] }))),
    ).then((arrs) => {
      const merged = arrs.flatMap((r) => r.responses || []);
      setResponses(merged);
      setLoading(false);
    });
  }, [campaignId, campaigns]);

  // Init Leaflet map sekali — clean up saat unmount.
  useEffect_rm(() => {
    if (!window.L || !mapEl.current || mapRef.current) return;
    const map = window.L.map(mapEl.current, {
      center: INDONESIA_CENTER,
      zoom: INDONESIA_ZOOM,
      scrollWheelZoom: true,
      zoomControl: true,
    });
    window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors',
      maxZoom: 19,
    }).addTo(map);
    mapRef.current = map;
    // Group cluster — auto-merge marker dekat saat zoom out
    clusterRef.current = window.L.markerClusterGroup({
      maxClusterRadius: 50,
      spiderfyOnMaxZoom: true,
    });
    map.addLayer(clusterRef.current);

    return () => {
      map.remove();
      mapRef.current = null;
      clusterRef.current = null;
    };
  }, []);

  // Re-render markers tiap kali responses / range berubah.
  useEffect_rm(() => {
    if (!mapRef.current || !clusterRef.current || !window.L) return;
    clusterRef.current.clearLayers();

    const cutoffMs = RANGE_OPTIONS.find((r) => r.id === range)?.ms;
    const cutoff = cutoffMs ? Date.now() - cutoffMs : null;

    // Resolve coordinate + region hierarchy untuk tiap respons:
    //   1. Pakai latitude/longitude kalau ada (GPS asli — paling akurat)
    //   2. Else, fallback ke region-text centroid lookup (perkiraan kota/provinsi)
    //   3. Else, skip (gak bisa diplot)
    // Filter province/kotakab dipakai dari hierarchy resolution.
    const candidates = [];
    for (const r of responses) {
      if (cutoff && new Date(r.submittedAt).getTime() < cutoff) continue;
      const hier = window.resolveRegionHierarchy ? window.resolveRegionHierarchy(r.region) : null;
      // Apply province / kotakab filter.
      if (provinceFilter && (!hier || hier.province !== provinceFilter)) continue;
      if (kotakabFilter && (!hier || hier.kotakab !== kotakabFilter)) continue;

      let lat = r.latitude;
      let lon = r.longitude;
      let approx = false;
      if (typeof lat !== 'number' || typeof lon !== 'number') {
        const ll = window.regionToLatLon ? window.regionToLatLon(r.region) : null;
        if (!ll) continue;
        [lat, lon] = ll;
        approx = true;
      }
      candidates.push({ r, lat, lon, approx, hier });
    }

    // Custom icon — solid biru untuk GPS asli, dashed amber untuk approximate.
    const gpsIcon = window.L.divIcon({
      className: 'rinta-gps-marker',
      html: '<div style="width:18px;height:18px;border-radius:50%;background:oklch(0.52 0.18 265);border:2.5px solid white;box-shadow:0 2px 6px rgba(0,0,0,0.35);"></div>',
      iconSize: [18, 18],
      iconAnchor: [9, 9],
    });
    const approxIcon = window.L.divIcon({
      className: 'rinta-approx-marker',
      html: '<div style="width:16px;height:16px;border-radius:50%;background:oklch(0.78 0.16 75 / 0.8);border:2px dashed oklch(0.55 0.16 75);box-shadow:0 1px 4px rgba(0,0,0,0.25);"></div>',
      iconSize: [16, 16],
      iconAnchor: [8, 8],
    });

    const markers = candidates.map(({ r, lat, lon, approx }) => {
      // Jitter sedikit untuk approx markers — supaya marker di centroid yang
      // sama (mis. 50 respons "Surabaya") tidak overlap persis di 1 titik.
      // Cluster akan tetap merge mereka, tapi saat zoom in, marker tersebar.
      const j = approx
        ? [lat + (Math.random() - 0.5) * 0.04, lon + (Math.random() - 0.5) * 0.04]
        : [lat, lon];
      const m = window.L.marker(j, { icon: approx ? approxIcon : gpsIcon });
      const time = new Date(r.submittedAt).toLocaleString('id-ID', {
        day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit',
      });
      const html = `
        <div style="font-size:12.5px;line-height:1.5;min-width:140px;">
          <b>${r.respondentName || 'Anonim'}</b><br>
          ${r.region || '—'}
          ${approx ? '<span style="color:oklch(0.55 0.16 75);font-size:10.5px;background:oklch(0.96 0.05 75);padding:1px 5px;border-radius:3px;margin-left:4px;">approx</span>' : ''}
          <br><span style="color:#888;font-size:11px;">${time}</span>
        </div>
      `;
      m.bindPopup(html);
      return m;
    });
    clusterRef.current.addLayers(markers);
    // Stash for stats below
    window.__rintaMapStats = {
      gps: candidates.filter((c) => !c.approx).length,
      approx: candidates.filter((c) => c.approx).length,
    };

    // Auto-fit ke markers kalau ada — atau tetap di Indonesia center kalau kosong.
    if (markers.length > 0) {
      const group = window.L.featureGroup(markers);
      mapRef.current.fitBounds(group.getBounds().pad(0.2), {
        maxZoom: 12,
        animate: true,
      });
    } else {
      mapRef.current.setView(INDONESIA_CENTER, INDONESIA_ZOOM);
    }
  }, [responses, range, provinceFilter, kotakabFilter]);

  // Region count (text-based) untuk side panel — terapkan SEMUA filter
  // (range + province + kotakab) supaya konsisten dengan marker map.
  const regionStats = (() => {
    const cutoffMs = RANGE_OPTIONS.find((r) => r.id === range)?.ms;
    const cutoff = cutoffMs ? Date.now() - cutoffMs : null;
    const m = new Map();
    for (const r of responses) {
      if (cutoff && new Date(r.submittedAt).getTime() < cutoff) continue;
      const hier = window.resolveRegionHierarchy ? window.resolveRegionHierarchy(r.region) : null;
      if (provinceFilter && (!hier || hier.province !== provinceFilter)) continue;
      if (kotakabFilter && (!hier || hier.kotakab !== kotakabFilter)) continue;
      const key = (r.region || 'Tidak diketahui').trim() || 'Tidak diketahui';
      m.set(key, (m.get(key) ?? 0) + 1);
    }
    return [...m.entries()]
      .map(([region, n]) => ({ region, n }))
      .sort((a, b) => b.n - a.n);
  })();

  const totalInRange = regionStats.reduce((s, r) => s + r.n, 0);
  // Re-compute coords stat — terapkan semua filter (range + provinsi + kotakab).
  const cutoffMs = RANGE_OPTIONS.find((r) => r.id === range)?.ms;
  const cutoff = cutoffMs ? Date.now() - cutoffMs : null;
  const filteredForStats = responses.filter((r) => {
    if (cutoff && new Date(r.submittedAt).getTime() < cutoff) return false;
    const hier = window.resolveRegionHierarchy ? window.resolveRegionHierarchy(r.region) : null;
    if (provinceFilter && (!hier || hier.province !== provinceFilter)) return false;
    if (kotakabFilter && (!hier || hier.kotakab !== kotakabFilter)) return false;
    return true;
  });
  const gpsCount = filteredForStats.filter((r) => typeof r.latitude === 'number').length;
  const approxCount = filteredForStats.filter((r) => {
    if (typeof r.latitude === 'number') return false;
    return window.regionToLatLon ? !!window.regionToLatLon(r.region) : false;
  }).length;
  const unmappable = filteredForStats.length - gpsCount - approxCount;

  return (
    <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
      {/* Header + filter bar */}
      <div style={{
        padding: '14px 18px', borderBottom: '1px solid var(--line)',
        display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
      }}>
        <div style={{ flex: 1, minWidth: 200 }}>
          <div style={{ fontSize: 13, fontWeight: 600 }}>Sebaran Responden</div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>
            {loading ? 'Memuat…'
              : totalInRange > 0
                ? `${totalInRange} respons · ${gpsCount} GPS asli · ${approxCount} dari region${unmappable > 0 ? ` · ${unmappable} tanpa lokasi` : ''}`
                : 'Belum ada respons di rentang waktu ini'}
          </div>
        </div>

        <select
          className="select"
          value={campaignId}
          onChange={(e) => setCampaignId(e.target.value)}
          style={{ width: 'auto', fontSize: 12.5, padding: '6px 28px 6px 10px' }}
        >
          <option value="all">Semua campaign</option>
          {campaigns.map((c) => (
            <option key={c.id} value={c.id}>{c.title}</option>
          ))}
        </select>

        <select
          className="select"
          value={provinceFilter}
          onChange={(e) => setProvinceFilter(e.target.value)}
          style={{ width: 'auto', fontSize: 12.5, padding: '6px 28px 6px 10px', maxWidth: 180 }}
          title="Filter provinsi"
        >
          <option value="">📍 Semua provinsi</option>
          {(window.PROVINCES || []).map((p) => (
            <option key={p} value={p}>{p}</option>
          ))}
        </select>

        <select
          className="select"
          value={kotakabFilter}
          onChange={(e) => setKotakabFilter(e.target.value)}
          disabled={!provinceFilter || kotakabOptions.length === 0}
          style={{
            width: 'auto', fontSize: 12.5, padding: '6px 28px 6px 10px', maxWidth: 180,
            opacity: !provinceFilter ? 0.5 : 1,
          }}
          title={provinceFilter ? 'Filter kabupaten/kota' : 'Pilih provinsi dulu'}
        >
          <option value="">🏙 Semua kota/kab</option>
          {kotakabOptions.map((k) => (
            <option key={k} value={k}>{k}</option>
          ))}
        </select>

        {(provinceFilter || kotakabFilter) && (
          <button
            className="btn btn-ghost"
            onClick={() => { setProvinceFilter(''); setKotakabFilter(''); }}
            style={{ padding: '6px 10px', fontSize: 11.5 }}
            title="Reset filter wilayah"
          >
            <I.X size={12} /> Reset
          </button>
        )}

        <div style={{ display: 'flex', background: 'var(--bg-2)', borderRadius: 8, padding: 2 }}>
          {RANGE_OPTIONS.map((r) => (
            <button key={r.id} onClick={() => setRange(r.id)} style={{
              border: 'none', background: range === r.id ? 'var(--surface)' : 'transparent',
              padding: '5px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500,
              color: range === r.id ? 'var(--ink)' : 'var(--ink-3)',
              boxShadow: range === r.id ? 'var(--shadow-sm)' : 'none', cursor: 'pointer',
            }}>{r.label}</button>
          ))}
        </div>
      </div>

      {/* Map + side panel */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 240px', gap: 0, height: 420 }}>
        <div style={{ position: 'relative' }}>
          <div ref={mapEl} style={{ height: '100%', background: 'var(--bg-2)' }} />
          {/* Legend overlay */}
          <div style={{
            position: 'absolute', bottom: 10, left: 10, zIndex: 400,
            background: 'rgba(255,255,255,0.95)', backdropFilter: 'blur(6px)',
            border: '1px solid var(--line)', borderRadius: 8,
            padding: '8px 10px', fontSize: 11, lineHeight: 1.6,
            boxShadow: 'var(--shadow-sm)',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ width: 10, height: 10, borderRadius: '50%', background: 'oklch(0.52 0.18 265)', border: '1.5px solid white', boxShadow: '0 1px 2px rgba(0,0,0,0.3)' }}></span>
              <span style={{ color: 'var(--ink-2)' }}>GPS asli</span>
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ width: 10, height: 10, borderRadius: '50%', background: 'oklch(0.78 0.16 75 / 0.8)', border: '1.5px dashed oklch(0.55 0.16 75)' }}></span>
              <span style={{ color: 'var(--ink-2)' }}>Approx (dari region)</span>
            </div>
          </div>
        </div>

        <div style={{
          borderLeft: '1px solid var(--line)', overflowY: 'auto',
          padding: '12px 14px',
        }}>
          <div style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600, marginBottom: 8 }}>
            Region teratas
          </div>
          {regionStats.length === 0 && (
            <div style={{ fontSize: 12, color: 'var(--ink-3)', fontStyle: 'italic' }}>
              Belum ada data.
            </div>
          )}
          {regionStats.slice(0, 12).map((r, i) => {
            const pct = totalInRange > 0 ? (r.n / totalInRange) * 100 : 0;
            return (
              <div key={r.region} style={{ marginBottom: 8 }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', fontSize: 12, marginBottom: 3 }}>
                  <span style={{
                    color: 'var(--ink-2)', fontWeight: i < 3 ? 600 : 500,
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 140,
                  }}>{r.region}</span>
                  <span className="mono" style={{ fontWeight: 600 }}>{r.n}</span>
                </div>
                <div style={{ height: 4, borderRadius: 999, background: 'var(--bg-2)', overflow: 'hidden' }}>
                  <div style={{ width: `${pct}%`, height: '100%', background: 'var(--primary)', borderRadius: 999 }} />
                </div>
              </div>
            );
          })}
          {regionStats.length > 12 && (
            <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 6, fontStyle: 'italic' }}>
              +{regionStats.length - 12} region lainnya
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { RegionalMap });
