/* Live data wiring for Portal Satu Data KKP (portaldata.kkp.go.id).
   The statistik API is public and CORS-open; GeoServer WMS renders as map imagery
   (no CORS needed for <img>/tile requests). Nothing here is mocked — if the
   fetch fails, callers should surface that rather than fabricate a number. */

/* Routed through our own dev-server.js proxy (same-origin) because
   portaldata.kkp.go.id's GeoServer sends no CORS headers and ArcGIS's
   WMSLayer requires fetch()-able, CORS-enabled tiles to composite. */
const KKP_LAYER_CATALOG_URL = 'https://portaldata.kkp.go.id/api/portal/list_all_layer?visibilitas_data=tampilkan&allowedroles=tersedia';
const OMS_LAUTRA_FEATURE_SERVER = 'https://services8.arcgis.com/mpSDBlkEzjS62WgX/ArcGIS/rest/services/OMS_Lautra_d/FeatureServer';
const OMS_LAUTRA_CATALOG = [
  ['Mangrove',0,'Ekosistem mangrove untuk pencarian kondisi, stok karbon, area, dan indikator carbon trade.'],
  ['Substrat Dasar',1,'Klasifikasi substrat dasar laut pada wilayah kajian OMS Lautra.'],
  ['Makroalga',2,'Sebaran makroalga pada wilayah kajian OMS Lautra.'],
  ['Lamun',3,'Sebaran ekosistem lamun pada wilayah kajian OMS Lautra.'],
  ['Terumbu Karang',4,'Sebaran terumbu karang untuk eksplorasi historis dan visualisasi bawah laut.'],
  ['Lokasi Indikatif OECM',5,'Lokasi indikatif Other Effective Area-based Conservation Measures.'],
  ['Kawasan Konservasi',6,'Geometri kawasan konservasi untuk skenario EVIKA dan analisis spasial.'],
  ['Kawasan yang ditetapkan',7,'Kawasan konservasi yang telah ditetapkan.'],
  ['Provincial Marine Zones (WKLP)',8,'Zona laut provinsi atau WKLP.'],
].map(([title,id,description])=>({
  id:'arcgis:oms-lautra:'+id,name:'oms_lautra_'+id,title,description,
  category:'data_eksternal',categoryLabel:'OMS Lautra · ArcGIS Online',workspace:'OMS_Lautra_d',
  featureServiceUrl:OMS_LAUTRA_FEATURE_SERVER+'/'+id,serviceUrl:OMS_LAUTRA_FEATURE_SERVER,
  serviceItemId:'b580f1d3409344388b05441a55b4ee0f',layerId:id,geometryType:'esriGeometryPolygon',
  spatialReference:'EPSG:3857',sourceStatus:'Data dummy / prototype',
  extent:{xmin:94.77,ymin:-11.2,xmax:141.02,ymax:6.28},
}));

/* Real, time-stamped ecosystem layers served by SIDAKO's GeoServer
   (workspace `oceanaccounts`), discovered from its own WMS GetCapabilities —
   these back the Marine Ecosystem Digital Twin's historical timeline. Only
   years that actually exist as layers are listed; the mangrove 2025 layer is
   named without the `spatial_` prefix the other years use, which is a real
   quirk of the source service, not a typo here. */
const SIDAKO_GIS_BASE = '/sidako-gis';
const DIGITAL_TWIN_YEARS = [2018, 2021, 2025];
const ECOSYSTEM_LAYERS = {
  coral: { 2018:'oceanaccounts:spatial_coral_2018', 2021:'oceanaccounts:spatial_coral_2021', 2025:'oceanaccounts:spatial_coral_2025' },
  mangrove: { 2018:'oceanaccounts:spatial_mangrove_2018', 2021:'oceanaccounts:spatial_mangrove_2021', 2025:'oceanaccounts:mangrove_2025' },
  seagrass: { 2018:'oceanaccounts:spatial_seagrass_2018', 2021:'oceanaccounts:spatial_seagrass_2021', 2025:'oceanaccounts:spatial_seagrass_2025' },
};
const ECOSYSTEM_LABELS = { coral:'Terumbu Karang', mangrove:'Mangrove', seagrass:'Lamun (Seagrass)' };
const ECOSYSTEM_COLOR = { coral:[255,111,60], mangrove:[46,163,89], seagrass:[64,168,222] };
const DIGITAL_TWIN_BOUNDARY_LAYERS = [
  { id:'provinces', label:'Batas Provinsi', layer:'oceanaccounts:administrative_provinces' },
  { id:'coastlines', label:'Garis Pantai', layer:'oceanaccounts:administrative_coastlines' },
  { id:'mpa', label:'Kawasan Konservasi', layer:'konservasi:data_kk_2025' },
];

const CATEGORY_LABELS = {
  statistik_spasial: 'Statistik Spasial',
  penguatan_daya_saing_produk_kelautan_dan_perikanan: 'Daya Saing Produk KP',
  pengelolaan_kelautan: 'Pengelolaan Kelautan',
  perikanan_budidaya: 'Perikanan Budidaya',
  perikanan_tangkap: 'Perikanan Tangkap',
  penyuluhan_dan_pengembangan_sdmkp: 'Penyuluhan & SDM KP',
  pengendalian_dan_pengawasan_mutu_hasil_kp: 'Pengendalian Mutu Hasil KP',
  pengawasan_sumber_daya_kelautan_dan_perikanan: 'Pengawasan Sumber Daya KP',
  bantuan_pemerintah: 'Bantuan Pemerintah',
  penataan_ruang_laut: 'Penataan Ruang Laut',
  data_eksternal: 'Data Eksternal',
};

let layerCatalogCache = null;
/* Flattens Portal Satu Data KKP's live layer catalog into one array, each entry
   carrying its real GeoServer workspace:name so it can be added straight to the
   map as a WMS overlay. */
async function fetchLayerCatalog(){
  if (layerCatalogCache) return layerCatalogCache;
  let json=null;
  try{
    const res = await fetch(KKP_LAYER_CATALOG_URL);
    if (res.ok) json=await res.json();
  }catch(_){/* OMS Lautra curated catalog remains available when Portal KKP is offline. */}
  const rows = [];
  for (const [catKey, cat] of Object.entries(json?.data||{})) {
    for (const layer of (cat.layers || [])) {
      if (!layer || !layer.name || layer.name === 'undefined') continue;
      const minX = parseFloat(layer.min_x), minY = parseFloat(layer.min_y);
      const maxX = parseFloat(layer.max_x), maxY = parseFloat(layer.max_y);
      rows.push({
        id: (layer.workspaces || catKey) + ':' + layer.name,
        name: layer.name,
        title: layer.title || layer.name,
        category: catKey,
        categoryLabel: CATEGORY_LABELS[catKey] || catKey,
        workspace: layer.workspaces || catKey,
        wmsLayer: (layer.workspaces || catKey) + ':' + layer.name,
        totalAttributes: layer.total_attributes,
        extent: (isFinite(minX) && isFinite(minY) && isFinite(maxX) && isFinite(maxY)) ? { xmin:minX, ymin:minY, xmax:maxX, ymax:maxY } : null,
      });
    }
  }
  rows.push(...OMS_LAUTRA_CATALOG);
  layerCatalogCache = rows;
  return rows;
}

/* Adapts a KKP catalog row into the metadata record shape used by Esri's
   geoportal-server-catalog (github.com/Esri/geoportal-server-catalog), which
   itself follows DCAT-US / ArcGIS Hub content conventions: identifier, title,
   description, resourceType, keywords, publisher, spatial extent, and a
   distribution list of {format, accessURL}. The underlying values are still
   live from portaldata.kkp.go.id — this only reshapes them into that standard
   record so the catalog UI and any future geoportal-compatible harvester can
   read it the same way. */
const GEOPORTAL_RESOURCE_TYPE = {
  statistik_spasial: 'Geographic Service',
  pengelolaan_kelautan: 'Geographic Dataset',
  perikanan_budidaya: 'Geographic Dataset',
  perikanan_tangkap: 'Geographic Dataset',
  data_eksternal: 'Dataset',
};

function toGeoportalRecord(row){
  if(row.documentUrl) return {
    identifier:row.id,
    title:row.title,
    description:row.description||'Dokumen publikasi dari SIDAKO KKP.',
    resourceType:'Document',
    keywords:[row.categoryLabel,row.documentFocus,'SIDAKO','KKP'].filter(Boolean),
    publisher:row.documentAuthor||'Kementerian Kelautan dan Perikanan Republik Indonesia',
    landingPage:'https://sidako.kkp.go.id/sidako/dokumen',
    modified:row.documentDate||null,
    spatial:null,
    distribution:[{format:'PDF',accessURL:row.documentUrl}],
  };
  const bbox = row.extent;
  return {
    identifier: row.id,
    title: row.title,
    description: row.description || ('Layer geospasial "' + row.title + '" pada kategori ' + row.categoryLabel + ', diterbitkan melalui GeoServer Portal Satu Data KKP.'),
    resourceType: GEOPORTAL_RESOURCE_TYPE[row.category] || 'Geographic Service',
    keywords: [row.categoryLabel, row.workspace, 'KKP', 'kelautan dan perikanan'],
    publisher: row.featureServiceUrl ? 'OMS Lautra · ArcGIS Online' : 'Kementerian Kelautan dan Perikanan Republik Indonesia',
    landingPage: row.featureServiceUrl ? 'https://www.arcgis.com/home/item.html?id='+row.serviceItemId : 'https://portaldata.kkp.go.id',
    modified: null,
    spatial: bbox ? {
      type: 'envelope',
      crs: 'EPSG:4326',
      coordinates: [[bbox.xmin, bbox.ymin], [bbox.xmax, bbox.ymax]],
    } : null,
    distribution: row.featureServiceUrl ? [
      {format:'ArcGIS Feature Service',accessURL:row.featureServiceUrl},
      {format:'ArcGIS REST Service',accessURL:row.serviceUrl},
    ] : [
      { format:'WMS', accessURL: window.KKP_GIS_BASE + '?SERVICE=WMS&REQUEST=GetMap&LAYERS=' + encodeURIComponent(row.wmsLayer) },
      { format:'WMS Capabilities', accessURL: window.KKP_GIS_BASE + '?SERVICE=WMS&REQUEST=GetCapabilities' },
    ],
  };
}

const KKP_GIS_BASE = '/kkp-gis/wms';
const KKP_STATS_URL = 'https://portaldata.kkp.go.id/api/statistik/provinsi';

const PROVINCES = [
  { id:'11', name:'ACEH', lat:5.5483, lon:95.3238 },
  { id:'12', name:'SUMATERA UTARA', lat:3.5952, lon:98.6722 },
  { id:'13', name:'SUMATERA BARAT', lat:-0.9471, lon:100.4172 },
  { id:'14', name:'RIAU', lat:0.5333, lon:101.45 },
  { id:'15', name:'JAMBI', lat:-1.6101, lon:103.6131 },
  { id:'16', name:'SUMATERA SELATAN', lat:-2.9761, lon:104.7754 },
  { id:'17', name:'BENGKULU', lat:-3.7928, lon:102.2608 },
  { id:'18', name:'LAMPUNG', lat:-5.4293, lon:105.2610 },
  { id:'19', name:'KEP. BANGKA BELITUNG', lat:-2.1316, lon:106.1169, aliases:['bangka belitung','babel'] },
  { id:'21', name:'KEPULAUAN RIAU', lat:0.9186, lon:104.4453 },
  { id:'31', name:'DKI JAKARTA', lat:-6.2088, lon:106.8456, aliases:['jakarta'] },
  { id:'32', name:'JAWA BARAT', lat:-6.9175, lon:107.6191 },
  { id:'33', name:'JAWA TENGAH', lat:-6.9932, lon:110.4203 },
  { id:'34', name:'DAERAH ISTIMEWA YOGYAKARTA', lat:-7.7956, lon:110.3695, aliases:['yogyakarta','jogja','diy'] },
  { id:'35', name:'JAWA TIMUR', lat:-7.2575, lon:112.7521 },
  { id:'36', name:'BANTEN', lat:-6.1149, lon:106.1503 },
  { id:'51', name:'BALI', lat:-8.6705, lon:115.2126 },
  { id:'52', name:'NUSA TENGGARA BARAT', lat:-8.5833, lon:116.1167, aliases:['ntb'] },
  { id:'53', name:'NUSA TENGGARA TIMUR', lat:-10.1772, lon:123.6070, aliases:['ntt'] },
  { id:'61', name:'KALIMANTAN BARAT', lat:-0.0263, lon:109.3425 },
  { id:'62', name:'KALIMANTAN TENGAH', lat:-2.2096, lon:113.9213 },
  { id:'63', name:'KALIMANTAN SELATAN', lat:-3.3186, lon:114.5944 },
  { id:'64', name:'KALIMANTAN TIMUR', lat:-0.5022, lon:117.1536 },
  { id:'65', name:'KALIMANTAN UTARA', lat:2.8385, lon:117.3676 },
  { id:'71', name:'SULAWESI UTARA', lat:1.4748, lon:124.8421 },
  { id:'72', name:'SULAWESI TENGAH', lat:-0.8917, lon:119.8707 },
  { id:'73', name:'SULAWESI SELATAN', lat:-5.1477, lon:119.4327 },
  { id:'74', name:'SULAWESI TENGGARA', lat:-3.9450, lon:122.4989 },
  { id:'75', name:'GORONTALO', lat:0.5435, lon:123.0568 },
  { id:'76', name:'SULAWESI BARAT', lat:-2.6785, lon:118.8886 },
  { id:'81', name:'MALUKU', lat:-3.6954, lon:128.1814 },
  { id:'82', name:'MALUKU UTARA', lat:0.7833, lon:127.3833 },
  { id:'91', name:'PAPUA', lat:-2.5337, lon:140.7181 },
  { id:'92', name:'PAPUA BARAT', lat:-0.8615, lon:134.0620 },
  { id:'93', name:'PAPUA SELATAN', lat:-8.4699, lon:140.4023 },
  { id:'94', name:'PAPUA TENGAH', lat:-3.3667, lon:135.4833 },
  { id:'95', name:'PAPUA PEGUNUNGAN', lat:-4.0847, lon:138.9386 },
  { id:'96', name:'PAPUA BARAT DAYA', lat:-0.8762, lon:131.2558 },
];

/* WPP-RI (wilayah pengelolaan perikanan) reference points, used only to re-centre
   the map when a WPP number is mentioned — the boundary itself is drawn live from
   the WMS layer below, this is just a camera hint. */
const WPP_FOCUS = {
  '571':{lat:5.4,lon:97.9},'572':{lat:1.0,lon:96.0},'573':{lat:-8.0,lon:104.0},
  '711':{lat:1.5,lon:107.5},'712':{lat:-4.5,lon:112.5},'713':{lat:-3.5,lon:119.0},
  '714':{lat:-4.8,lon:122.8},'715':{lat:-0.4,lon:121.9},'716':{lat:2.0,lon:125.0},
  '717':{lat:-2.5,lon:136.5},'718':{lat:-7.5,lon:138.5},
};

const TOPICS = [
  { key:'nelayan', keywords:['nelayan'], field:'nelayan', sub:'year_max', label:'Jumlah nelayan', unit:'orang', wmsLayer:'statistik_spasial:Jumlah_Nelayan_Provinsi' },
  { key:'pembudidaya', keywords:['pembudidaya','budi daya','budidaya'], field:'pembudidaya', sub:'year_max', label:'Jumlah pembudidaya', unit:'orang', wmsLayer:'statistik_spasial:Jumlah_Pembudidaya_Provinsi' },
  { key:'aki', keywords:['konsumsi ikan','angka konsumsi','aki'], field:'aki', sub:'year_max', label:'Angka Konsumsi Ikan (AKI)', unit:'kg/kapita/tahun', wmsLayer:'statistik_spasial:Angka_Konsumsi_Ikan_Provinsi' },
  { key:'tangkap', keywords:['ikan tangkap','produksi tangkap','tangkap'], field:'ikan_tangkap', sub:'year_max', label:'Produksi perikanan tangkap', unit:'ton' },
  { key:'kapal', keywords:['kapal'], field:'kapal', sub:'year_max', label:'Jumlah kapal perikanan', unit:'unit' },
  { key:'garam', keywords:['garam'], field:'prod_garam', sub:'year_max', label:'Produksi garam', unit:'ton' },
  { key:'pelabuhan', keywords:['pelabuhan'], field:'pelabuhan', sub:'jmlh_pelabuhan', label:'Jumlah pelabuhan perikanan', unit:'unit' },
  { key:'pelaku_usaha', keywords:['pelaku usaha'], field:'pelaku_usaha', sub:'jmlh_pelaku_usaha', label:'Jumlah pelaku usaha', unit:'entitas' },
];

function normalize(s){ return s.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g,''); }

function detectProvince(text){
  const t = normalize(text);
  let best = null, bestLen = 0;
  for (const p of PROVINCES) {
    const names = [p.name, ...(p.aliases||[])].map(normalize);
    for (const n of names) {
      if (t.includes(n) && n.length > bestLen) { best = p; bestLen = n.length; }
    }
  }
  return best;
}

function detectWpp(text){
  const m = text.match(/\b(57[1-3]|71[1-8])\b/);
  return m ? m[1] : null;
}

function detectTopic(text){
  const t = normalize(text);
  for (const top of TOPICS) {
    if (top.keywords.some(k => t.includes(normalize(k)))) return top;
  }
  return null;
}

/* Parses a free-text question into a queryable intent. Returns null fields when
   nothing recognisable was said, so the caller can ask a clarifying question
   instead of guessing. */
function parseQuery(text){
  const province = detectProvince(text);
  const wpp = detectWpp(text);
  const topic = detectTopic(text) || TOPICS[0];
  return { province, wpp, topic };
}

let statsCache = null;
async function fetchProvinceStats(){
  if (statsCache) return statsCache;
  const res = await fetch(KKP_STATS_URL);
  if (!res.ok) throw new Error('Portal Satu Data KKP tidak merespons (' + res.status + ')');
  const json = await res.json();
  statsCache = json.data;
  return statsCache;
}

/* Standard Web Mercator tiling grid (matches Esri/Google/OSM basemaps): used to
   convert a WebTileLayer's level/row/col into the bbox a WMS GetMap needs. */
const WEB_MERCATOR_ORIGIN = { x:-20037508.342787, y:20037508.342787 };
const WEB_MERCATOR_INITIAL_RESOLUTION = 156543.03392804097;

function tileToWmsUrl(base, layerName, level, row, col, size){
  const resolution = WEB_MERCATOR_INITIAL_RESOLUTION / Math.pow(2, level);
  const xmin = WEB_MERCATOR_ORIGIN.x + col * size * resolution;
  const ymax = WEB_MERCATOR_ORIGIN.y - row * size * resolution;
  const xmax = xmin + size * resolution;
  const ymin = ymax - size * resolution;
  const params = new URLSearchParams({
    SERVICE:'WMS', VERSION:'1.3.0', REQUEST:'GetMap', FORMAT:'image/png', TRANSPARENT:'TRUE',
    STYLES:'', WIDTH:String(size), HEIGHT:String(size), CRS:'EPSG:3857',
    LAYERS:layerName, BBOX:[xmin,ymin,xmax,ymax].join(','),
  });
  return base + '?' + params.toString();
}

function formatNumber(n){
  const v = Number(n);
  if (!isFinite(v)) return String(n);
  return v.toLocaleString('id-ID');
}

/* SIDAKO (sidako.kkp.go.id) — Direktorat Konservasi Ekosistem's blue carbon /
   EVIKA (conservation-area effectiveness score) platform. Routed through the
   same dev-server.js proxy as the KKP GIS layers: SIDAKO sends no CORS headers
   either, and the analyze endpoint needs POST body forwarding. */
const SIDAKO_BASE = '/sidako-proxy';

const BLUE_CARBON_KEYWORDS = ['blue carbon','karbon biru','karbon laut','serapan karbon','carbon sequestration','stok karbon'];
const EVIKA_KEYWORDS = ['evika','efektivitas pengelolaan','status pengelolaan'];

function detectBlueCarbon(text){ const t = normalize(text); return BLUE_CARBON_KEYWORDS.some(k => t.includes(normalize(k))); }
function detectEvika(text){ const t = normalize(text); return EVIKA_KEYWORDS.some(k => t.includes(normalize(k))); }

/* A ~0.5°x0.5° sample box around a point — NOT a real administrative or
   ecosystem boundary. Used only because our chat interface has no polygon
   drawing tool; the real SIDAKO app lets a user draw or upload the actual
   area. Every caller must label this as an illustrative sample area. */
function sampleBoxAround(lat, lon, sizeDeg){
  const half = (sizeDeg || 0.5) / 2;
  const ring = [
    [lon-half, lat-half], [lon+half, lat-half], [lon+half, lat+half], [lon-half, lat+half], [lon-half, lat-half],
  ];
  return {
    ring,
    geojson: { type:'Polygon', coordinates:[ring] },
    extent: { xmin:lon-half, ymin:lat-half, xmax:lon+half, ymax:lat+half },
  };
}

async function submitBlueCarbonAnalysis(geometry){
  const res = await fetch(SIDAKO_BASE + '/ocean-accounts-api/area-analysis/analyze?async_mode=true', {
    method:'POST', headers:{ 'content-type':'application/json' },
    body: JSON.stringify({
      geometry, multi_year_baseline:true, progressive_multi_year:true,
      analysis_types:['administrative','coastline','mangrove','seagrass','coral'],
    }),
  });
  if (!(res.status === 202 || res.ok)) throw new Error('SIDAKO ocean-accounts-api tidak merespons (' + res.status + ')');
  return res.json();
}

async function pollBlueCarbonJob(jobId, { maxTries = 20, intervalMs = 2000 } = {}){
  for (let i = 0; i < maxTries; i++) {
    const res = await fetch(SIDAKO_BASE + '/ocean-accounts-api/jobs/' + jobId);
    if (res.ok) {
      const json = await res.json();
      if (!['queued','running','processing'].includes(json.status)) return json;
      if (i === maxTries - 1) return json;
    }
    await new Promise(r => setTimeout(r, intervalMs));
  }
  throw new Error('Analisis blue carbon SIDAKO tidak selesai tepat waktu.');
}

/* SIDAKO's own `/api/area_value` and `/api/rank_area` routes (unlike
   ocean-accounts-api) sit behind an anti-bot guard that bounces any request
   without a browser-fingerprinted TLS/session handshake to an obfuscated URL —
   confirmed by testing directly, including with a real session cookie, from
   our own proxy. Rather than fake a live call we can't actually make, this is
   a real, dated snapshot pulled straight from that endpoint (tahun=2025,
   captured 2026-09-18) — all 127 kawasan, verbatim. `fetchEvikaAreaValue`
   keeps an async signature so call sites don't care that this is static. */
const EVIKA_SNAPSHOT_DATE = '2026-09-18';
const EVIKA_SNAPSHOT_2025 = {"berkelanjutan":{"Kawasan Konservasi Di Perairan Di Wilayah Kepulauan Alor Provinsi Nusa Tenggara Timur":[94.20558139534883,646,277072.6],"Kawasan Konservasi Kepulauan Padaido dan Laut Sekitarnya di Provinsi Papua":[90.3035778175313,573,177411.35],"Kawasan Konservasi Kepulauan Waigeo Sebelah Barat":[89.06175313059035,576,267209.16],"Kawasan Konservasi Kepulauan Raja Ampat dan Laut Sekitarnya":[88.50944543828265,577,57875.75],"Kawasan Konservasi di Perairan Kepulauan Raja Ampat di Provinsi Papua Barat Daya":[86.4602862254025,579,1348459.47],"Kawasan Konservasi Laut Banda dan Sekitarnya di Provinsi Maluku":[87.59713774597496,601,2501.98],"Kawasan Konservasi Kepulauan Kapoposang dan Laut Sekitarnya di Provinsi Sulawesi Selatan":[90.97817531305904,614,49923.55],"Kawasan Konservasi Perairan Nasional Laut Sawu dan Sekitarnya di Provinsi Nusa Tenggara Timur":[92.99731663685152,649,3355352.82],"Kawasan Konservasi Pulau Gili Air, Gili Meno, dan Gili Trawangan di Provinsi Nusa Tenggara Barat":[92.5128801431127,655,2268.59],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Pantai Penyu Pangumbahan dan Perairan Sekitarnya  di Kabupaten Sukabumi Provinsi Jawa Barat":[90.71273703041145,687,2706.09],"Kawasan Konservasi Kepulauan Anambas dan Laut Sekitarnya di Provinsi Kepulauan Riau":[86.7361717352415,696,1265401.51],"Kawasan Konservasi Pulau Pieh dan Laut Sekitarnya di Provinsi Sumatera Barat":[90.60772808586762,697,39920]},"optimum":{"Kawasan Konservasi Perairan Teluk Cempi dan Perairan Sekitarnya di Provinsi Nusa Tenggara Barat":[62.19359570661896,662,22257.45],"Kawasan Konservasi Perairan Pesisir Timur Pulau Weh Kota Sabang di Provinsi Aceh":[65.86951699463329,570,3207.98],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Teluk Berau dan Teluk Nusalasi-Van Den Bosch di Provinsi Papua Barat":[66.00443649373882,574,346807.87],"Kawasan Konservasi Perairan Buruway, Arguni, Kaimana, Teluk Etna, dan Perairan Sekitarnya di Provinsi Papua Barat":[52.10536672629696,575,499804.13],"Kawasan Konservasi Pesisir dan Pulau-pulau Kecil Aceh Jaya dan Perairan di Sekitarnya di Provinsi Aceh":[50.4397495527728,578,50105.18],"Kawasan Konservasi Misool Utara":[67.55710196779964,580,308777.35],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Pulau Kei Kecil, Pulau-Pulau, dan Perairan Sekitarnya di Kabupaten Maluku Tenggara Provinsi Maluku":[74.32325581395348,582,150000],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Pulau Koon, Pulau Gorogos, Pulau Nukus, Pulau Neden, dan Perairan Sekitarnya di Provinsi Maluku":[61.292093023255816,583,9900.87],"Kawasan Konservasi di Perairan Kepulauan Lease di Provinsi Maluku":[70.17910554561718,584,67484.19],"Kawasan Konservasi di Perairan Pulau Ay dan Pulau Rhun Provinsi Maluku":[66.69449016100178,587,61178.53],"Kawasan Konservasi Perairan Aceh Besar di Provinsi Aceh":[63.66100178890876,588,29615.63],"Kawasan Konservasi di Perairan Pulau Buano di Provinsi Maluku":[58.788372093023256,589,31886.86],"Kawasan Konservasi Perairan Pulau Pinang, Pulau Siumat, dan Pulau Simanaha di Provinsi Aceh":[67.28726296958855,590,44404.1],"Kawasan Konservasi Perairan Sawo-Lahewa dan Perairan di Sekitarnya Kabupaten Nias Utara Provinsi Sumatera Utara":[52.37309481216458,593,29130.47],"Kawasan Konservasi di Perairan Seram Utara dan Seram Utara Barat di Provinsi Maluku":[60.54146690518783,594,106710.86],"Kawasan Konservasi Kepulauan Aru Bagian Tenggara dan Laut Sekitarnya di Provinsi Maluku":[81.02812164579606,602,94874.14],"Kawasan Konservasi di Perairan Kepulauan Guraici di Provinsi Maluku Utara":[61.53055456171735,603,91538.99],"Kawasan Konservasi di Perairan Kepulauan Widi di Provinsi Maluku Utara":[59.7597137745975,605,315117.92],"Kawasan Konservasi Perairan Pulau Mare dan Perairan Sekitarnya di Provinsi Maluku Utara":[60.82271914132379,607,7060.87],"Kawasan Konservasi di Perairan Pulau Makian dan Pulau Moti di Provinsi Maluku Utara":[55.46042933810376,608,67349],"Kawasan Konservasi Perairan Pulau Rao-Tanjung Dehegila dan Perairan Sekitarnya di Provinsi Maluku Utara":[68.34561717352415,609,65892.42],"Kawasan Konservasi di Perairan Teluk Moramo di Provinsi Sulawesi Tenggara":[52.79338103756708,610,21902.34],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Banggai, Banggai Laut, Banggai Kepulauan, dan Perairan Sekitarnya di Provinsi Sulawesi Tengah":[62.07992844364938,619,856649.13],"KAWASAN KONSERVASI PESISIR DAN PULAU-PULAU KECIL MOROWALI, MOROWALI UTARA, DAN PERAIRAN SEKITARNYA DI PROVINSI SULAWESI TENGAH":[72.68726296958855,620,292910.12],"KKD Parigi Moutong, Poso, Tojo Una-Una":[52.17631484794276,621,128689.86],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Kepulauan Tatoareng dan Perairan Sekitarnya di Provinsi Sulawesi Utara":[61.505187835420394,624,164251.94],"KKD Kepulauan Siau Tagulandang Biaro":[56.59695885509839,626,39931.2],"KKD Minahasa Utara":[54.04561717352415,627,25531.26],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Kepulauan Derawan dan Perairan Sekitarnya di Kabupaten Berau Provinsi Kalimantan Timur":[80.07119856887299,632,285548.95],"Kawasan Konservasi di Perairan Mahakam Wilayah Hulu Kabupaten Kutai Kartanegara":[59.10250447227192,633,42667.99],"Kawasan Konservasi Perairan Angsana, Sungai Loban, Pulau Laut-Pulau Sembilan, Kepulauan Sambargelap":[65.30758497316637,635,179659.89],"Kawasan Konservasi Perairan Gosong Senggora, Gosong Sepagar, Gosong Baras Basah, Teluk Bogam Sampai Tanjung Keluang, Serta Perairan Sekitarnya Di Provinsi Kalimantan Tengah":[67.90429338103758,642,61362.24],"Kawasan Konservasi di Perairan di Wilayah Flores Timur di Provinsi Nusa Tenggara Timur":[55.51785330948121,647,150069.35],"Kawasan Konservasi Perairan Selat Bunga Laut Kabupaten Kepulauan Mentawai di Provinsi Sumatera Barat":[67.72772808586762,650,129566],"Kawasan Konservasi di Perairan di Wilayah Pesisir Selatan di Provinsi Sumatera Barat":[57.570518783542035,651,175583.56],"Kawasan Konservasi di Perairan di Wilayah Kota Padang Provinsi Sumatera Barat":[52.204508050089444,654,2188.7],"Kawasan Konservasi di Perairan di Wilayah Kota Pariaman di Provinsi Sumatera Barat":[83.21738819320215,656,11778.22],"Kawasan Konservasi di Perairan di WIlayah Batang Gasan Padang Pariaman di Provinsi Sumatera Barat":[74.48322003577817,657,735.93],"Kawasan Konservasi di Perairan Gili Balu di Provinsi Nusa Tenggara Barat":[68.80200357781754,658,5845.67],"Kawasan Konservasi di Perairan di Wilayah Pasaman Barat Provinsi Sumatera Barat":[64.27445438282648,660,6122.14],"Kawasan Konservasi Perairan Pulau Liang, Pulau Ngali, dan Perairan Sekitarnya di Provinsi Nusa Tenggara Barat":[67.86561717352416,661,32692.9],"Kawasan Konservasi Perairan Gili Sulat dan Gili Lawang, dan Perairan Sekitarnya di Provinsi Nusa Tenggara Barat":[78.36200357781753,663,10000],"Kawasan Konservasi Perairan Gili Tangkong, Gili Nanggu, Gili Sudak, dan Perairan Sekitarnya di Provinsi Nusa Tenggara Barat":[74.3221824686941,664,21132.82],"KK Pulau Lipan dan Pulau Rakit":[65.2413595706619,666,26670.8],"KK Pulau Panjang":[54.71363148479428,667,22185.14],"Kawasan Konservasi Perairan Nusa Penida di Provinsi Bali":[76.7942754919499,671,20057],"Kawasan Konservasi di Perairan Kepulauan Aruah di Provinsi Riau":[63.36228980322004,673,18536.1],"Kawasan Konservasi Perairan Gili Ketapang dan Perairan Sekitarnya di Provinsi Jawa Timur":[66.06708407871199,674,476.78],"Kawasan Konservasi di Perairan di Wilayah Indragiri Hilir Provinsi Riau":[59.437960644007156,675,126097.64],"Kawasan Konservasi di Perairan di Wilayah Pantai Selatan Bantul Daerah Istimewa Yogyakarta":[61.623899821109134,676,695.89],"Kawasan Konservasi di Perairan di Wilayah Timur Pulau Bintan Provinsi Kepulauan Riau":[68.11252236135957,677,138561.42],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Ujungnegoro-Roban Kabupaten Batang di Provinsi Jawa Tengah":[52.525223613595706,678,3520.28],"Kawasan Konservasi di Perairan di Wilayah Karang Jahe Provinsi Jawa Tengah":[51.95724508050089,681,33.65],"Kawasan Konservasi di Perairan di Wilayah Karang Jeruk Provinsi Jawa Tengah":[59.348300536672625,682,238.16],"Kawasan Konservasi di Perairan di Wilayah Pulau Panjang Provinsi Jawa Tengah":[52.34186046511628,684,494.25],"Kawasan Konservasi di Perairan di Wilayah Pangandaran Provinsi Jawa Barat":[67.73434704830053,686,38810.15],"Kawasan Konservasi Maritim Hmas Perth di Perairan Provinsi Banten":[51.73516994633273,688,99.94],"KKD Way Kambas":[77.88697674418606,691,60420.98]},"minimum":{"Kawasan Konservasi Di Perairan Di Wilayah Pulauh Salah Nama Provinsi Sumatera Utara":[23.255813953488374,645,3806.14],"KKD Pulau Kolepom":[13.023255813953488,571,356337.9],"Kawasan Konservasi Biak Numfor":[13.788014311270125,572,49062.44],"Kawasan Konservasi Seribu Satu Sungai Teoenebikia di Perairan Sorong Selatan di Provinsi Papua Barat":[8.5912343470483,581,349133.13],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Aceh Tamiang dan Perairan Sekitarnya di Provinsi Aceh":[34.76890876565295,586,2750.71],"Kawasan Konservasi Perairan Aceh Barat Daya di Provinsi Aceh":[34.54976744186046,591,16017.45],"Kawasan Konservasi Perairan Aceh Selatan di Provinsi Aceh":[42.483577817531305,592,3590.34],"Kawasan Konservasi di Perairan di Wilayah Kepulauan Tanimbar Provinsi Maluku":[44.024651162790704,595,312181.7],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Tapanuli Tengah dan Perairan Sekitarnya di Provinsi Sumatera Utara":[38.328729874776386,596,84429.07],"Kawasan Konservasi di Perairan di Wilayah Damer Provinsi Maluku":[34.626404293381036,597,297143.91],"Kawasan Konservasi di Perairan di Wilayah Mdona Hiera, Lakor, Moa dan Letti di Provinsi Maluku":[30.76923076923077,598,371722.43],"Kawasan Konservasi di Perairan di Wilayah Kepulauan Romang Provinsi Maluku":[33.46808586762075,599,274845.74],"Kawasan Konservasi di Perairan di Wilayah Kepulauan Babar Provinsi Maluku":[37.02593917710197,600,370527.09],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Kepulauan Sula dan Perairan Sekitarnya di Provinsi Maluku Utara":[34.75989266547406,606,120723.88],"Kawasan Konservasi di Perairan Pulau Wawonii di Provinsi Sulawesi Tenggara":[38.24379248658318,611,27044.9909071],"Kawasan Konservasi di Perairan di Wilayah Kepulauan Balabalakang Provinsi Sulawesi Barat":[21.337209302325583,612,184469.31],"Kawasan Konservasi di Perairan di Wilayah Liukang Tangaya Provinsi Sulawesi Selatan":[44.354418604651165,613,505862.34],"KKD Kayuadi":[12.848837209302326,615,6899.43],"KKPD  Pasi Gusung":[16.91860465116279,616,1769.73],"KKD Pulau Panikiang":[12.848837209302326,617,496.8],"Kawasan Konservasi di Perairan di Wilayah Liukang Tupabbiring Provinsi Sulawesi Selatan":[38.52561717352415,618,63407.23],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Donggala, Buol, Tolitoli, dan Perairan Sekitarnya di Provinsi Sulawesi Tengah":[47.42447227191414,622,60042.72],"Kawasan Konservasi Teluk Gorontalo Provinsi Gorontalo":[44.248407871198566,623,76580.48],"Kawasan Konservasi di Wilayah Laut Sulawesi":[4.127906976744185,625,603511.3],"KKD Bitung":[3.546511627906977,628,9659.39],"Kawasan Konservasi di Perairan di Wilayah Binusan dan Pulau Sinelak Provinsi Kalimantan Utara":[31.26565295169946,629,900.11],"Kawasan Konservasi di Perairan di Wilayah Tanjung Palas Timur Provinsi Kalimantan Utara":[31.63831842576029,630,24581.97],"Kawasan Konservasi di Perairan Bontang di Provinsi Kalimantan Timur":[45.51649373881932,631,3499.53],"Kawasan Konservasi Muara Badak dan Marangkayu Kutai Kartanegara":[25.520250447227188,634,3985.21],"Kawasan Konservasi Perairan Kubu Raya dan Kayong Utara di Provinsi Kalimantan Barat":[26.879821109123434,636,115723.63],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Kendawangan dan Perairan Sekitarnya di Provinsi Kalimantan Barat":[28.9191771019678,637,164595.74],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Kubu Raya dan Perairan Sekitarnya di Provinsi Kalimantan Barat":[43.081180679785334,638,134409.14],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Paloh dan Perairan Sekitarnya di Provinsi Kalimantan Barat":[28.485330948121646,639,168291.06],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Pulau Randayan dan Perairan Sekitarnya di Provinsi Kalimantan Barat":[33.838676207513416,640,61654.59],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Jeen Womom Kabupaten Tambrauw dan Perairan Sekitarnya di Provinsi Papua Barat":[46.38282647584973,641,32250.86],"Kawasan Konservasi Pesisir dan Pulau-Pulau Kecil Pulau-Pulau Batu Nias Selatan dan Perairan Sekitarnya di Provinsi Sumatera Utara":[42.88887298747764,643,44939.22],"Kawasan Konservasi di Perairan di Wilayah Pulau Berhala Provinsi Sumatera Utara":[23.707513416815743,644,3762.62],"KAWASAN KONSERVASI DI PERAIRAN DI WILAYAH PULAU PINI PROVINSI SUMATERA UTARA":[23.255813953488374,648,44336.01],"Kawasan Konservasi di Perairan di Wilayah Lembata di Provinsi Nusa Tenggara Timur":[32.19735241502683,652,199688.38],"Kawasan Konservasi di Perairan di Wilayah Sikka di Provinsi Nusa Tengara Timur":[37.459713774597496,653,75133.46],"Kawasan Konservasi Perairan Gili Banta dan Perairan Sekitarnya di Provinsi Nusa Tenggara Barat":[46.013631484794274,659,40276.54],"KK Kramat, Bedil dan Temudong":[47.74440071556351,665,1955.55],"Kawasan Konservasi di Perairan di Wilayah Buleleng Provinsi Bali":[30.330948121645797,668,18060.18],"Kawasan Konservasi di Perairan di Wilayah Karangasem Provinsi Bali":[30.559033989266545,669,5478.41],"Kawasan Konservasi di Perairan di Wilayah Agam Provinsi Sumatera Barat":[18.72540250447227,670,6535.98],"Kawasan Konservasi Maritim Teluk Benoa di Perairan Provinsi Bali":[17.08855098389982,672,1243.41],"Kawasan Konservasi di Periaran di Wilayah Betahwalang Provinsi Jawa Tengah":[28.837209302325583,698,244.88],"KAWASAN KONSERVASI DI PERAIRAN DI WILAYAH BINTAN II PROVINSI KEPULAUAN RIAU":[17.906976744186046,679,843609.3],"Kawasan Konservasi Perairan Gugusan Pulau-Pulau Momparang dan Perairan Sekitarnya Kabupaten Belitung Timur di Provinsi Kepulauan Bangka Belitung":[39.825581395348834,680,124320.7],"Kawasan Konservasi Perairan Belitung di Provinsi Kepulauan Bangka Belitung":[41.38640429338104,683,391820.23],"Kawasan Konservasi di Perairan Pulau Biawak di Provinsi Jawa Barat":[37.03635062611807,685,54847.49],"Kawasan Konservasi Perairan Teluk Kiluan dan Perairan Sekitarnya di Provinsi Lampung":[49.87602862254025,689,72211.68],"Kawasan Konservasi di Perairan di WIlayah Batang Gasan Padang Pariaman di Provinsi Sumatera Barat":[17.325581395348838,690,735.93],"Kawasan Konservasi Suaka Perikanan Tuing - Bangka":[45.96601073345259,692,7372.5],"Kawasan Konservasi Ketugar Perlang":[42.391055456171735,693,11358.29],"KKD Ngambur":[39.818032200357784,694,4584.87],"Kawasan Konservasi Pulau Lepar dan Pulau Pongok":[37.7906976744186,695,92519.25]}};

const evikaCache = {};
async function fetchEvikaAreaValue(tahun){
  const year = String(tahun || 2025);
  if (evikaCache[year]) return evikaCache[year];
  try {
    const res = await fetch('/sidako-proxy/api/area_value?tahun=' + encodeURIComponent(year));
    if (!res.ok) throw new Error('SIDAKO tidak merespons ('+res.status+')');
    const json = await res.json();
    const groups = json.data || {};
    const liveRows = [];
    for (const status of ['berkelanjutan','optimum','minimum']) {
      for (const [name, v] of Object.entries(groups[status] || {})) {
        liveRows.push({ name, status, score:Number(v[0])||0, id:v[1], luasHa:Number(v[2])||0, year:Number(year), source:'SIDAKO live' });
      }
    }
    if (!liveRows.length) throw new Error('Data EVIKA kosong');
    evikaCache[year] = liveRows;
    return liveRows;
  } catch (error) {
    // Keep the verified 2025 snapshot available when the official service is
    // temporarily down. Other years never fall back to generated values.
    if (year !== '2025') throw error;
    const rows = [];
    for (const status of ['berkelanjutan','optimum','minimum']) {
      for (const [name, v] of Object.entries(EVIKA_SNAPSHOT_2025[status] || {})) {
        rows.push({ name, status, score:v[0], id:v[1], luasHa:v[2], year:2025, source:'SIDAKO snapshot' });
      }
    }
    evikaCache[year] = rows;
    return rows;
  }
}

function findEvikaArea(rows, fragment){
  const t = normalize(fragment);
  if (!t) return null;
  let best = null, bestLen = Infinity;
  for (const r of rows) {
    const n = normalize(r.name);
    if (n.includes(t) && n.length < bestLen) { best = r; bestLen = n.length; }
  }
  return best;
}

const EVIKA_STATUS_LABEL = { berkelanjutan:'Berkelanjutan (Emas)', optimum:'Optimum (Perak)', minimum:'Minimum (Perunggu)' };

Object.assign(window, {
  KKP_GIS_BASE, KKP_STATS_URL, KKP_LAYER_CATALOG_URL, PROVINCES, WPP_FOCUS, TOPICS, CATEGORY_LABELS,
  parseQuery, fetchProvinceStats, fetchLayerCatalog, toGeoportalRecord, formatNumber, detectProvince, detectWpp, detectTopic, tileToWmsUrl,
  SIDAKO_BASE, detectBlueCarbon, detectEvika, sampleBoxAround, submitBlueCarbonAnalysis, pollBlueCarbonJob,
  fetchEvikaAreaValue, findEvikaArea, EVIKA_STATUS_LABEL, EVIKA_SNAPSHOT_DATE,
  SIDAKO_GIS_BASE, DIGITAL_TWIN_YEARS, ECOSYSTEM_LAYERS, ECOSYSTEM_LABELS, ECOSYSTEM_COLOR, DIGITAL_TWIN_BOUNDARY_LAYERS,
});
