// Real data from Naturvårdsverket APIs.
// WFS SkyddadePunkter: point centroids with bbox support, GeoJSON output.
// REST /omrade/{id}/Gällande: full record including beskrivning, fetched on demand.

const _WFS = "https://geodata.naturvardsverket.se/naturvardsregistret/wfs/v2";
const _REST = "https://geodata.naturvardsverket.se/naturvardsregistret/rest/v3";

// Haversine distance in km
function _haversine(lat1, lon1, lat2, lon2) {
  const R = 6371;
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a = Math.sin(dLat / 2) ** 2 +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLon / 2) ** 2;
  return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

// Compute centroid of a GeoJSON MultiPolygon (average of outer ring vertices).
function _centroid(geometry) {
  const ring = geometry.coordinates[0][0]; // outer ring of first polygon
  let sumLon = 0, sumLat = 0;
  for (const [lon, lat] of ring) { sumLon += lon; sumLat += lat; }
  return { lat: sumLat / ring.length, lon: sumLon / ring.length };
}

// Fetch reserves near a lat/lon. Uses SkyddadeOmraden (polygon layer) which
// contains Naturreservat and Nationalpark. Returns array sorted by distance.
window.fetchReservesNearby = async function (userLat, userLon, radiusDeg = 0.35) {
  const latSpan = radiusDeg;
  const lonSpan = radiusDeg / Math.cos(userLat * Math.PI / 180);
  const bbox = [
    (userLat - latSpan).toFixed(6),
    (userLon - lonSpan).toFixed(6),
    (userLat + latSpan).toFixed(6),
    (userLon + lonSpan).toFixed(6),
  ].join(",");

  const url =
    `${_WFS}?service=WFS&version=2.0.0&request=GetFeature` +
    `&typeNames=Naturvardsregistret_WFS:SkyddadeOmraden` +
    `&outputFormat=GEOJSON&srsName=EPSG:4326` +
    `&BBOX=${bbox}&count=1000`;

  const resp = await fetch(url);
  if (!resp.ok) throw new Error(`WFS ${resp.status}`);
  const data = await resp.json();

  const allowed = new Set(["Naturreservat", "Nationalpark", "Kommunalt naturreservat"]);

  return data.features
    .filter(f => allowed.has(f.properties.SKYDDSTYP))
    .map((f, i) => {
      const { lat, lon } = _centroid(f.geometry);
      const dist = _haversine(userLat, userLon, lat, lon);
      const yearStr = f.properties.URSPR_BESLUTSDATUM;
      const ar = yearStr ? parseInt(yearStr.slice(0, 4)) : null;
      const typ = f.properties.SKYDDSTYP === "Kommunalt naturreservat"
        ? "Naturreservat" : f.properties.SKYDDSTYP;
      return {
        id: f.properties.NVRID,
        namn: f.properties.NAMN,
        typ,
        storlek: f.properties.AREA_HA,
        ar,
        avstand: Math.round(dist * 10) / 10,
        lat,
        lon,
        geojson: f.geometry, // actual polygon for boundary rendering
        beskrivning: null,
        _seed: (i + 1) * 1337,
      };
    })
    .sort((a, b) => a.avstand - b.avstand);
};

// Fetch the beskrivning for one reserve (called when user opens detail sheet).
window.fetchReserveDetail = async function (id) {
  try {
    const resp = await fetch(`${_REST}/omrade/${id}/G%C3%A4llande`);
    if (!resp.ok) return null;
    const data = await resp.json();
    return data.beskrivning || null;
  } catch {
    return null;
  }
};

// Project real lat/lon to SVG coordinate space (0..1000).
// User location is always at SVG (500, 500). Scale: ~30 km across 1000 SVG units.
window.latLonToSvg = function (lat, lon, userLat, userLon) {
  const SVG_PER_KM = 33.3;
  const kmLat = 111.32;
  const kmLon = 111.32 * Math.cos(userLat * Math.PI / 180);
  return {
    x: 500 + (lon - userLon) * kmLon * SVG_PER_KM,
    y: 500 - (lat - userLat) * kmLat * SVG_PER_KM,
  };
};

// Build a soft irregular boundary polygon around SVG point (cx, cy).
function _seeded(seed) {
  let s = seed;
  return () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
}
window.boundaryPath = function (cx, cy, areaHa, seed) {
  const baseR = Math.min(28 + Math.sqrt(Math.max(areaHa || 1, 1)) * 1.6, 90);
  const rand = _seeded(seed);
  const points = 14;
  const pts = [];
  for (let i = 0; i < points; i++) {
    const a = (i / points) * Math.PI * 2;
    const r = baseR * (0.72 + rand() * 0.55);
    pts.push([cx + Math.cos(a) * r, cy + Math.sin(a) * r]);
  }
  let d = `M ${pts[0][0].toFixed(1)} ${pts[0][1].toFixed(1)}`;
  for (let i = 0; i < pts.length; i++) {
    const p0 = pts[(i - 1 + pts.length) % pts.length];
    const p1 = pts[i];
    const p2 = pts[(i + 1) % pts.length];
    const p3 = pts[(i + 2) % pts.length];
    const t = 0.18;
    const c1x = p1[0] + (p2[0] - p0[0]) * t;
    const c1y = p1[1] + (p2[1] - p0[1]) * t;
    const c2x = p2[0] - (p3[0] - p1[0]) * t;
    const c2y = p2[1] - (p3[1] - p1[1]) * t;
    d += ` C ${c1x.toFixed(1)} ${c1y.toFixed(1)}, ${c2x.toFixed(1)} ${c2y.toFixed(1)}, ${p2[0].toFixed(1)} ${p2[1].toFixed(1)}`;
  }
  return d + " Z";
};

// Ray-casting point-in-polygon for a GeoJSON ring ([lon, lat] pairs).
function _pointInRing(lon, lat, ring) {
  let inside = false;
  for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
    const xi = ring[i][0], yi = ring[i][1];
    const xj = ring[j][0], yj = ring[j][1];
    if ((yi > lat) !== (yj > lat) && lon < ((xj - xi) * (lat - yi)) / (yj - yi) + xi) {
      inside = !inside;
    }
  }
  return inside;
}

// Returns true if lat/lon is inside any polygon of a GeoJSON MultiPolygon geometry.
function _pointInMultiPolygon(lon, lat, geometry) {
  for (const polygon of geometry.coordinates) {
    if (_pointInRing(lon, lat, polygon[0])) return true; // outer ring only
  }
  return false;
}

// Returns the first reserve whose polygon contains the given lat/lon, or null.
window.findReserveContaining = function (lat, lon, reserves) {
  return reserves.find(r => r.geojson && _pointInMultiPolygon(lon, lat, r.geojson)) || null;
};

// Decorative stylized map shapes (background only — not geographic).
window.MAP_SHAPES = {
  land: "M -40 80 C 60 40, 180 60, 280 50 C 380 40, 480 90, 580 70 C 680 50, 780 80, 880 60 C 960 50, 1040 90, 1080 160 L 1080 940 C 1020 980, 920 960, 820 980 C 720 1000, 620 970, 520 990 C 420 1010, 320 970, 220 985 C 120 1000, 20 970, -40 920 Z",
  lake1: "M 700 180 C 760 150, 860 160, 900 220 C 940 280, 920 340, 850 360 C 780 380, 700 360, 670 300 C 640 240, 660 200, 700 180 Z",
  lake2: "M 80 700 C 140 670, 240 680, 290 740 C 320 790, 290 850, 220 870 C 140 890, 60 860, 50 800 C 40 750, 50 720, 80 700 Z",
  river: "M -20 280 C 80 300, 140 260, 220 290 C 300 320, 360 380, 440 400 C 520 420, 580 480, 620 560 C 660 640, 700 720, 780 780 C 860 840, 940 860, 1040 880",
  forest1: "M 320 480 C 400 460, 480 480, 500 540 C 520 600, 460 640, 380 630 C 300 620, 280 540, 320 480 Z",
  forest2: "M 580 380 C 640 360, 700 380, 710 430 C 720 480, 660 510, 600 500 C 540 490, 540 410, 580 380 Z",
  forest3: "M 140 420 C 200 400, 260 420, 270 470 C 280 520, 220 540, 160 530 C 100 520, 100 440, 140 420 Z",
  forest4: "M 800 600 C 860 580, 920 610, 920 660 C 920 710, 860 730, 800 720 C 740 710, 750 620, 800 600 Z",
  road1: "M -20 500 C 100 510, 240 480, 380 510 C 520 540, 660 520, 800 550 C 900 570, 980 560, 1040 580",
  road2: "M 500 -20 C 510 100, 480 220, 510 340 C 540 460, 520 580, 550 700 C 570 800, 540 900, 560 1040",
};
