/* ParcelLookup — self-contained module.
   Type a Polish cadastral parcel number (full TERYT id, e.g. 141201_1.0001.6509,
   OR "obręb name + number", e.g. "Krzewina 134"); it fetches the parcel from the
   GUGiK ULDK service and hands the resolved parcel up via onParcelResolved(parcel).
   The PARENT owns "the current parcel" and overwrites it — this module never keeps
   a list. Pass the active parcel back in via the optional `currentParcel` prop.

   Props:
     • onParcelResolved(parcel)  — fired with the resolved parcel object (required)
     • currentParcel             — the currently active parcel, shown until replaced

   Parcel object shape (matches the ULDK result attributes, in order):
     { id, voivodeship, county, commune, region, parcel, geom_wkt }
*/
(function () {
  const { useState } = React;

  // ---- one-time style injection (uses the host design's CSS vars w/ fallbacks) ----
  const CSS = `
  .pl-card{background:var(--surface,#fbf9f4);border:1px solid var(--line,#ddd6c8);border-radius:var(--radius,4px);box-shadow:var(--shadow,0 1px 2px rgba(35,32,26,.05),0 8px 28px -16px rgba(35,32,26,.22));overflow:hidden;font-family:var(--font-sans,"IBM Plex Sans",system-ui,sans-serif);color:var(--ink,#23201a);}
  .pl-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:14px 18px;border-bottom:1px solid var(--line,#ddd6c8);}
  .pl-title{font-family:var(--font-serif,"Spectral",Georgia,serif);font-size:16px;font-weight:600;margin:0;}
  .pl-tag{font-size:11px;color:var(--ink-faint,#8c8576);}
  .pl-body{padding:16px 18px;display:flex;flex-direction:column;gap:14px;}
  .pl-field{display:flex;flex-direction:column;gap:7px;}
  .pl-label{font-size:12.5px;font-weight:600;}
  .pl-hint{font-size:10.5px;color:var(--ink-faint,#8c8576);}
  .pl-row{display:flex;gap:8px;}
  .pl-input{flex:1;min-width:0;height:38px;padding:0 11px;border:1px solid var(--line-strong,#c7bfac);border-radius:var(--radius,4px);background:var(--surface-2,#f0ece2);color:var(--ink,#23201a);font-family:var(--font-mono,"IBM Plex Mono",ui-monospace,monospace);font-size:13px;outline:none;}
  .pl-input:focus{border-color:var(--accent,#9a6a3a);}
  .pl-btn{flex:none;height:38px;padding:0 16px;border:1px solid var(--accent,#9a6a3a);border-radius:var(--radius,4px);background:var(--accent,#9a6a3a);color:#fff;font-family:var(--font-sans,"IBM Plex Sans",sans-serif);font-size:13px;font-weight:600;cursor:pointer;transition:.14s;}
  .pl-btn:hover{filter:brightness(1.06);}
  .pl-btn:disabled{opacity:.5;cursor:not-allowed;}
  .pl-notice{font-size:11.5px;line-height:1.4;border-radius:var(--radius,4px);padding:8px 11px;display:flex;gap:8px;align-items:flex-start;}
  .pl-notice .pl-ic{width:14px;height:14px;flex:none;margin-top:1px;}
  .pl-notice-warn{color:var(--warn,#b07d2e);background:color-mix(in srgb,var(--warn,#b07d2e) 12%,transparent);}
  .pl-notice-err{color:var(--low,#a8503e);background:color-mix(in srgb,var(--low,#a8503e) 12%,transparent);}
  .pl-loading{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--ink-soft,#5c564a);padding:4px 0;}
  .pl-spin{width:15px;height:15px;border:2px solid var(--line-strong,#c7bfac);border-top-color:var(--accent,#9a6a3a);border-radius:50%;animation:pl-spin .7s linear infinite;flex:none;}
  @keyframes pl-spin{to{transform:rotate(360deg);}}
  .pl-picker{display:flex;flex-direction:column;gap:6px;}
  .pl-picker-h{font-size:12px;font-weight:600;color:var(--ink-soft,#5c564a);}
  .pl-opt{display:flex;align-items:center;justify-content:space-between;gap:10px;text-align:left;border:1px solid var(--line,#ddd6c8);border-radius:var(--radius,4px);background:var(--surface-2,#f0ece2);padding:9px 11px;cursor:pointer;transition:.14s;}
  .pl-opt:hover{border-color:var(--accent,#9a6a3a);background:var(--accent-soft,#e8dac6);}
  .pl-opt-main{font-size:13px;font-weight:600;}
  .pl-opt-sub{font-size:11px;color:var(--ink-faint,#8c8576);margin-top:1px;}
  .pl-opt-go{font-family:var(--font-mono,monospace);font-size:11px;color:var(--accent-ink,#6f4a22);flex:none;}
  .pl-active{border-top:1px solid var(--line,#ddd6c8);padding-top:14px;display:flex;flex-direction:column;gap:12px;}
  .pl-active-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;}
  .pl-active-id{font-family:var(--font-mono,monospace);font-size:13px;font-weight:600;color:var(--accent-ink,#6f4a22);word-break:break-all;}
  .pl-active-lbl{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint,#8c8576);flex:none;}
  .pl-attrs{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line,#ddd6c8);border:1px solid var(--line,#ddd6c8);border-radius:var(--radius,4px);overflow:hidden;}
  .pl-attr{background:var(--surface,#fbf9f4);padding:9px 11px;}
  .pl-attr-k{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint,#8c8576);margin-bottom:3px;}
  .pl-attr-v{font-size:13px;font-weight:500;}
  .pl-map{display:block;width:100%;height:auto;background:var(--plan-bg,#fbf9f4);border:1px solid var(--line,#ddd6c8);border-radius:var(--radius,4px);}
  .pl-map-empty{display:grid;place-items:center;height:120px;font-family:var(--font-mono,monospace);font-size:11px;color:var(--ink-faint,#8c8576);background:var(--surface-2,#f0ece2);border:1px dashed var(--line-strong,#c7bfac);border-radius:var(--radius,4px);}
  .pl-poly{fill:color-mix(in srgb,var(--accent,#9a6a3a) 18%,transparent);stroke:var(--accent,#9a6a3a);stroke-width:1.6;stroke-linejoin:round;}
  .pl-empty{font-size:12.5px;color:var(--ink-faint,#8c8576);font-style:italic;border-top:1px solid var(--line,#ddd6c8);padding-top:14px;}
  .pl-mapcap{font-family:var(--font-mono,monospace);font-size:10px;fill:var(--ink-faint,#8c8576);letter-spacing:.04em;}
  `;
  if (!document.getElementById("parcel-lookup-styles")) {
    const s = document.createElement("style");
    s.id = "parcel-lookup-styles";
    s.textContent = CSS;
    document.head.appendChild(s);
  }

  const ATTRS = "id,voivodeship,county,commune,region,parcel,geom_wkt";
  const ENDPOINT = (id) =>
    "https://uldk.gugik.gov.pl/?request=GetParcelByIdOrNr&id=" +
    encodeURIComponent(id) + "&result=" + ATTRS + "&srid=4326";

  // ---- ULDK plain-text parser ----------------------------------------------
  // First line = count of matches (-1 = error). Each next line = one parcel,
  // pipe-delimited in the same order as ATTRS; geom_wkt is a WKT POLYGON.
  function parseULDK(text) {
    const lines = (text || "").replace(/\r/g, "").split("\n").map((l) => l.trim()).filter(Boolean);
    if (!lines.length) return { count: 0, parcels: [] };
    const count = parseInt(lines[0], 10);
    if (isNaN(count) || count <= 0) return { count: isNaN(count) ? -1 : count, parcels: [] };
    const keys = ATTRS.split(",");
    const parcels = lines.slice(1).map((line) => {
      const parts = line.split("|");
      const o = {};
      keys.forEach((k, i) => { o[k] = (parts[i] || "").trim(); });
      return o;
    });
    return { count, parcels };
  }

  // ---- WKT → rings of [lon,lat] --------------------------------------------
  function parseWKT(wkt) {
    if (!wkt) return [];
    return [...wkt.matchAll(/\(([^()]+)\)/g)].map((m) =>
      m[1].split(",").map((p) => p.trim().split(/\s+/).map(Number)).filter((p) => p.length >= 2 && !isNaN(p[0]) && !isNaN(p[1]))
    ).filter((r) => r.length >= 3);
  }

  // ---- offline fallback samples (used only when the live fetch is blocked) ---
  const poly = (cx, cy) =>
    "POLYGON((" + [
      [cx, cy], [cx + 0.0016, cy], [cx + 0.0016, cy + 0.0007],
      [cx + 0.0009, cy + 0.0007], [cx + 0.0009, cy + 0.0017],
      [cx, cy + 0.0017], [cx, cy],
    ].map((p) => p[0].toFixed(6) + " " + p[1].toFixed(6)).join(", ") + "))";

  const SAMPLES = [
    { id: "141201_1.0001.6509", voivodeship: "mazowieckie", county: "Warszawa", commune: "Warszawa-Żoliborz", region: "Marymont", parcel: "6509", geom_wkt: poly(21.0002, 52.2620) },
    { id: "020101_1.0012.134", voivodeship: "dolnośląskie", county: "bolesławiecki", commune: "Bolesławiec", region: "Krzewina", parcel: "134", geom_wkt: poly(15.1500, 51.1800) },
    { id: "320801_2.0034.134", voivodeship: "zachodniopomorskie", county: "gryfiński", commune: "Trzcińsko-Zdrój", region: "Krzewina", parcel: "134", geom_wkt: poly(14.6000, 53.0100) },
  ];

  function matchSamples(q) {
    const query = (q || "").trim();
    if (!query) return [];
    const byId = SAMPLES.filter((s) => s.id === query || s.id.startsWith(query));
    if (byId.length) return byId;
    const m = query.match(/^(.*?)[\s,]+(\d+\w*)$/);
    if (m) {
      const name = m[1].trim().toLowerCase(), num = m[2];
      return SAMPLES.filter((s) => s.region.toLowerCase().startsWith(name) && s.parcel === num);
    }
    return [];
  }

  // ---- geometry preview ------------------------------------------------------
  function MapPreview({ wkt }) {
    const rings = parseWKT(wkt);
    if (!rings.length) return <div className="pl-map-empty">brak geometrii</div>;
    const lats = rings.flat().map((p) => p[1]);
    const latMean = lats.reduce((a, b) => a + b, 0) / lats.length;
    const kx = Math.cos(latMean * Math.PI / 180) || 1; // rough aspect correction
    const proj = rings.map((r) => r.map(([lon, lat]) => [lon * kx, lat]));
    const xs = proj.flat().map((p) => p[0]), ys = proj.flat().map((p) => p[1]);
    const minX = Math.min(...xs), maxX = Math.max(...xs), minY = Math.min(...ys), maxY = Math.max(...ys);
    const W = 260, H = 168, pad = 20;
    const sx = (maxX - minX) || 1e-9, sy = (maxY - minY) || 1e-9;
    const sc = Math.min((W - 2 * pad) / sx, (H - 2 * pad) / sy);
    const ox = (W - sc * sx) / 2, oy = (H - sc * sy) / 2;
    const X = (x) => ox + (x - minX) * sc;
    const Y = (y) => H - (oy + (y - minY) * sc); // flip: lat increases upward
    const polys = proj.map((r) => r.map(([x, y]) => X(x).toFixed(1) + "," + Y(y).toFixed(1)).join(" "));
    return (
      <svg className="pl-map" viewBox={"0 0 " + W + " " + H} preserveAspectRatio="xMidYMid meet">
        <defs>
          <pattern id="pl-grid" width="13" height="13" patternUnits="userSpaceOnUse">
            <path d="M13 0 L0 0 0 13" fill="none" stroke="var(--plan-line,#b7ae9b)" strokeWidth="0.4" opacity="0.3" />
          </pattern>
        </defs>
        <rect width={W} height={H} fill="url(#pl-grid)" />
        {polys.map((p, i) => <polygon key={i} points={p} className="pl-poly" />)}
        <text x="8" y={H - 7} className="pl-mapcap">WGS84 · obrys działki</text>
      </svg>
    );
  }

  function Attr({ k, v }) {
    return (
      <div className="pl-attr">
        <div className="pl-attr-k">{k}</div>
        <div className="pl-attr-v">{v || "—"}</div>
      </div>
    );
  }

  const Ic = {
    info: () => <svg className="pl-ic" viewBox="0 0 16 16"><circle cx="8" cy="8" r="6.5" fill="none" stroke="currentColor" strokeWidth="1.3" /><line x1="8" y1="7" x2="8" y2="11.5" stroke="currentColor" strokeWidth="1.3" /><circle cx="8" cy="4.7" r="0.8" fill="currentColor" /></svg>,
    warn: () => <svg className="pl-ic" viewBox="0 0 16 16"><path d="M8 2 L15 14 L1 14 Z" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" /><line x1="8" y1="6.5" x2="8" y2="10" stroke="currentColor" strokeWidth="1.3" /><circle cx="8" cy="11.8" r="0.7" fill="currentColor" /></svg>,
  };

  // ---- main component --------------------------------------------------------
  function ParcelLookup({ currentParcel, onParcelResolved }) {
    const [query, setQuery] = useState("");
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [matches, setMatches] = useState(null);   // array when >1 match
    const [preview, setPreview] = useState(false);   // true = live data unavailable

    const resolve = (parcel) => {
      setMatches(null);
      setError(null);
      if (onParcelResolved) onParcelResolved(parcel);
    };

    const handleResult = (count, parcels) => {
      if (count === -1 || parcels.length === 0) {
        setError("Nie znaleziono działki o podanym numerze.");
        return;
      }
      if (parcels.length === 1) resolve(parcels[0]);
      else setMatches(parcels);
    };

    const fallback = (q) => {
      setPreview(true);
      const found = matchSamples(q);
      if (found.length === 0) setError("Nie znaleziono działki (dane podglądowe). Spróbuj np. „Krzewina 134” lub 141201_1.0001.6509.");
      else if (found.length === 1) resolve(found[0]);
      else setMatches(found);
    };

    const lookup = async () => {
      const q = query.trim();
      if (!q || loading) return;
      setLoading(true); setError(null); setMatches(null);
      try {
        const res = await fetch(ENDPOINT(q));
        if (!res.ok) throw new Error("HTTP " + res.status);
        const text = await res.text();
        const { count, parcels } = parseULDK(text);
        setPreview(false);
        handleResult(count, parcels);
      } catch (e) {
        // ULDK sends no CORS headers → browser fetch is blocked in preview.
        fallback(q);
      } finally {
        setLoading(false);
      }
    };

    const onKey = (e) => { if (e.key === "Enter") lookup(); };

    return (
      <section className="pl-card">
        <div className="pl-head">
          <h2 className="pl-title">Wyszukiwarka działki</h2>
          <span className="pl-tag mono">ULDK · GUGiK</span>
        </div>
        <div className="pl-body">
          <div className="pl-field">
            <span className="pl-label">Numer działki lub TERYT</span>
            <span className="pl-hint">np. 141201_1.0001.6509 lub „Krzewina 134”</span>
            <div className="pl-row">
              <input className="pl-input" type="text" value={query} placeholder="Wpisz identyfikator lub obręb + numer…"
                onChange={(e) => setQuery(e.target.value)} onKeyDown={onKey} spellCheck={false} />
              <button className="pl-btn" onClick={lookup} disabled={loading || !query.trim()}>Wczytaj działkę</button>
            </div>
          </div>

          {loading && (
            <div className="pl-loading"><span className="pl-spin" />Wczytywanie działki z ULDK…</div>
          )}

          {!loading && preview && !error && (
            <div className="pl-notice pl-notice-warn">{Ic.info()}<span>Podgląd: dane na żywo (ULDK) niedostępne w tym środowisku — pokazuję przykładowe działki.</span></div>
          )}

          {!loading && error && (
            <div className="pl-notice pl-notice-err">{Ic.warn()}<span>{error}</span></div>
          )}

          {!loading && matches && (
            <div className="pl-picker">
              <span className="pl-picker-h">Znaleziono {matches.length} działki — wybierz właściwą:</span>
              {matches.map((p, i) => (
                <button key={i} className="pl-opt" onClick={() => resolve(p)}>
                  <span>
                    <div className="pl-opt-main">{p.region} {p.parcel}</div>
                    <div className="pl-opt-sub">{p.commune} · {p.county} · {p.voivodeship}</div>
                  </span>
                  <span className="pl-opt-go mono">wybierz →</span>
                </button>
              ))}
            </div>
          )}

          {currentParcel ? (
            <div className="pl-active">
              <div className="pl-active-h">
                <span className="pl-active-id mono">{currentParcel.id || (currentParcel.region + " " + currentParcel.parcel)}</span>
                <span className="pl-active-lbl">aktywna działka</span>
              </div>
              <div className="pl-attrs">
                <Attr k="Działka" v={currentParcel.parcel} />
                <Attr k="Obręb" v={currentParcel.region} />
                <Attr k="Gmina" v={currentParcel.commune} />
                <Attr k="Powiat" v={currentParcel.county} />
                <Attr k="Województwo" v={currentParcel.voivodeship} />
                <Attr k="TERYT" v={currentParcel.id} />
              </div>
              <MapPreview wkt={currentParcel.geom_wkt} />
            </div>
          ) : (
            <div className="pl-empty">Brak aktywnej działki — wczytaj działkę powyżej.</div>
          )}
        </div>
      </section>
    );
  }

  window.ParcelLookup = ParcelLookup;
})();
