/* ===== form.jsx — Borehole Entry Form (4 tabs) ===== */

/* SPT/ISPT is intentionally NOT a field-app tab — the crew has no SPT rigs yet.
   The IsptTab component + addIspt + the log.ispt data field are kept (unused
   here) so SPT can be re-enabled later without rework, and so ISPT data that
   arrives via import/admin still round-trips untouched. */
const TABS = [
  { key: "loca", lbl: "Location", ags: "LOCA" },
  { key: "geos", lbl: "Välimäärang", ags: "GEOS" },
  { key: "samp", lbl: "Samples", ags: "SAMP" },
  { key: "photos", lbl: "Photos", ags: "PHOT" },
];

/* ---- GPS proximity check (LOCA tab) ----
   Coordinates come from the imported site plan and are NOT overwritten by a
   GPS fix. The button takes a fix, converts it to L-EST97 and reports the
   distance to the planned point, so the crew can verify they are standing at
   the right borehole before drilling. Audit fields saved on the log:
   gpsDist (m to plan) · gpsAcc (fix accuracy) · gpsLat/gpsLon/gpsTs (raw fix).
   Fallback: a hole with no coordinates yet (ad-hoc, no imported plan) gets
   its position FROM the fix, like the old capture flow. */
function distVerdict(dist, acc) {
  if (dist == null) return "";
  const tol = 10 + Math.min(acc || 0, 30); /* fix uncertainty widens the green zone, capped */
  return dist <= tol ? "good" : dist <= 75 ? "ok" : "bad";
}

function GpsCheck({ d, set }) {
  const [busy, setBusy] = useState(false);
  const [fresh, setFresh] = useState(false);   /* checked this session (vs saved earlier) */
  const [filled, setFilled] = useState(false); /* fallback: coords were filled from the fix */
  const [err, setErr] = useState("");
  const hasPlan = parseFloat(d.east) > 0 && parseFloat(d.north) > 0;
  const run = () => {
    if (!navigator.geolocation) { setErr("GPS pole selles seadmes saadaval"); return; }
    setBusy(true); setErr("");
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        setBusy(false); setFresh(true);
        const c = pos.coords, acc = Math.round(c.accuracy);
        const fix = RPStore.wgsToLest(c.latitude, c.longitude);
        if (!hasPlan) {
          /* no planned coordinates — fill them from the fix (old behaviour) */
          setFilled(true);
          set("east", fix.y.toFixed(2));
          set("north", fix.x.toFixed(2));
          set("lat", +c.latitude.toFixed(6));
          set("lon", +c.longitude.toFixed(6));
          set("gpsAcc", acc);
          set("gpsDist", 0);
          set("posSource", "gps");
          return;
        }
        setFilled(false);
        const dE = fix.y - parseFloat(d.east), dN = fix.x - parseFloat(d.north);
        set("gpsDist", Math.round(Math.sqrt(dE * dE + dN * dN)));
        set("gpsAcc", acc);
        set("gpsLat", +c.latitude.toFixed(6));
        set("gpsLon", +c.longitude.toFixed(6));
        set("gpsTs", new Date().toISOString());
      },
      (e) => { setBusy(false); setErr("GPS viga: " + (e.message || ("kood " + e.code))); },
      { enableHighAccuracy: true, timeout: 12000, maximumAge: 0 }
    );
  };
  const dist = d.gpsDist != null && d.gpsDist !== "" ? +d.gpsDist : null;
  const acc = d.gpsAcc != null && d.gpsAcc !== "" ? +d.gpsAcc : null;
  const q = distVerdict(dist, acc);
  const weak = acc != null && acc > 25;
  return (
    <div className="gpswrap">
      <div className="gpsrow">
        <button type="button" className="btn btn-ghost gpsbtn" onClick={run} disabled={busy}>
          <Icon name="gps" size={17} /> {busy ? "Otsin satelliite…" : (dist != null ? "Kontrolli uuesti" : "Kontrolli asukohta GPS-iga")}
        </button>
        {err && <span className="gpsmsg mono bad">{err}</span>}
        {!err && dist != null && (
          <span className={"gpsmsg mono " + q}>
            <span className="gpsdot"></span>
            {fresh ? "" : "Salvestatud · "}plaanist {dist} m{acc != null ? " (±" + acc + " m)" : ""}
          </span>
        )}
      </div>
      {!err && filled && (
        <div className="gpshint ok">Plaani koordinaadid puudusid — asukoht võeti GPS-ist (±{acc} m). Tavavoos tulevad koordinaadid imporditud asendiplaanist.</div>
      )}
      {!err && !filled && fresh && q === "good" && (
        <div className="gpshint good">Oled plaanitud puurimispunktis — võid alustada.</div>
      )}
      {!err && !filled && dist != null && q === "ok" && (
        <div className="gpshint ok">Plaanitud punkt on {dist} m eemal{weak ? " ja fiks on nõrk (±" + acc + " m) — liigu lagedale ja kontrolli uuesti" : " — kontrolli, kas oled õige augu juures"}.</div>
      )}
      {!err && !filled && dist != null && q === "bad" && (
        <div className="gpshint bad">Vale koht? Plaanitud punkt on {dist} m eemal. Kontrolli puuraugu ID-d või liigu plaani järgi õigesse punkti.</div>
      )}
    </div>
  );
}

function Field({ label, ags, children, className = "" }) {
  return (
    <div className={"field " + className}>
      <label>{label}{ags && <span className="ags">{ags}</span>}</label>
      {children}
    </div>
  );
}

/* ---- Tab 1: LOCATION ---- */
/* Borehole ID carries its type as a prefix. reTypeId swaps the prefix while
   keeping the running number; suggestBoreholeId picks the next free number for
   a given type within the project. */
function reTypeId(id, typeCode) {
  var s = String(id || "").trim();
  // strip any known type prefix (longest-first) to isolate the number/suffix
  var rest = s;
  for (var i = 0; i < BOREHOLE_TYPE_CODES.length; i++) {
    var c = BOREHOLE_TYPE_CODES[i];
    if (s.toUpperCase().indexOf(c.toUpperCase()) === 0) { rest = s.slice(c.length); break; }
  }
  rest = rest.replace(/^[\s\-_/]+/, ""); // drop separators left behind
  return typeCode + rest;
}
function suggestBoreholeId(pid, typeCode) {
  var holes = (window.BOREHOLES && window.BOREHOLES[pid]) || [];
  var esc = typeCode.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
  var re = new RegExp("^" + esc + "0*(\\d+)$", "i");
  var max = 0;
  holes.forEach(function (h) { var m = String(h.id).match(re); if (m) max = Math.max(max, +m[1]); });
  return typeCode + (max + 1);
}

function LocaTab({ d, set, onType, locked, onToggleLock }) {
  var known = BOREHOLE_TYPES.some(function (t) { return t[0] === d.type; });
  return (
    <div className="formstack">
      <div className={"lockbar" + (locked ? " on" : "")}>
        <span className="lockbar-ic"><Icon name={locked ? "lock" : "lockopen"} size={16} /></span>
        <div className="lockbar-txt">
          <b>{locked ? "Admin määras ID, tüübi ja asukoha" : "Väljad avatud muutmiseks"}</b>
          <span>{locked ? "Imporditud asendiplaanist — tavaliselt ei muudeta välitingimustes." : "Muuda ettevaatlikult ja kontrolli admini andmetega."}</span>
        </div>
        <button type="button" className="lockbtn" onClick={onToggleLock}>
          <Icon name={locked ? "lockopen" : "lock"} size={15} /> {locked ? "Ava" : "Lukusta"}
        </button>
      </div>
      <div className="grid2">
        <Field label="Borehole ID" ags="LOCA_ID">
          <input className="input mono" value={d.id} disabled={locked} onChange={(e) => set("id", e.target.value)} />
        </Field>
        <Field label="Tüüp" ags="LOCA_TYPE">
          <select className="select" value={d.type} disabled={locked} onChange={(e) => onType(e.target.value)}>
            {BOREHOLE_TYPES.map(([c, n]) => <option key={c} value={c}>{c} — {n}</option>)}
            {!known && <option value={d.type}>{d.type}</option>}
          </select>
        </Field>
      </div>
      <div className="grid2">
        <Field label="Easting Y (L-EST97)" ags="LOCA_NATE">
          <input className="input mono" inputMode="decimal" placeholder="0.00" value={d.east} disabled={locked} onChange={(e) => { set("east", e.target.value); set("posSource", "manual"); set("gpsDist", null); }} />
        </Field>
        <Field label="Northing X (L-EST97)" ags="LOCA_NATN">
          <input className="input mono" inputMode="decimal" placeholder="0.00" value={d.north} disabled={locked} onChange={(e) => { set("north", e.target.value); set("posSource", "manual"); set("gpsDist", null); }} />
        </Field>
      </div>
      {d.posSource === "plan" && (
        <div className="posplan">
          <Icon name="map" size={14} /> Asukoht plaanist (imporditud) — kontrolli GPS-iga, et seisad õige punkti juures
        </div>
      )}
      <GpsCheck d={d} set={set} />
      <Field label="Final depth (m)" ags="LOCA_FDEP">
        <input className="input mono" inputMode="decimal" placeholder="0.00" value={d.depth} onChange={(e) => set("depth", e.target.value)} />
      </Field>
      <div className="grid2">
        <Field label="Vesi ilmus (m) — puurimisel" ags="WSTG_DPTH">
          <input className="input mono" inputMode="decimal" placeholder="tühi = ei kohatud" value={d.veeStrike || ""} onChange={(e) => set("veeStrike", e.target.value)} />
        </Field>
        <Field label="Veetase stabiliseerunud (m)" ags="WSTD_POST">
          <input className="input mono" inputMode="decimal" placeholder="pärast seismist" value={d.veetase || ""} onChange={(e) => set("veetase", e.target.value)} />
        </Field>
      </div>
      <div className="grid2">
        <Field label="Start date" ags="LOCA_STAR">
          <input className="input" type="date" value={d.start} onChange={(e) => set("start", e.target.value)} />
        </Field>
        <Field label="End date" ags="LOCA_ENDD">
          <input className="input" type="date" value={d.end} onChange={(e) => set("end", e.target.value)} />
        </Field>
      </div>
      <Field label="Engineer" ags="LOCA_ENG">
        <input className="input" value={d.engineer} onChange={(e) => set("engineer", e.target.value)} />
      </Field>
      <Field label="Contractor" ags="LOCA_CR">
        <input className="input" value={d.contractor} onChange={(e) => set("contractor", e.target.value)} />
      </Field>
      <Field label="Method" ags="LOCA_TYPE">
        <select className="select" value={d.method} onChange={(e) => set("method", e.target.value)}>
          <option>Light cable percussion</option>
          <option>Rotary</option>
          <option>Trial pit</option>
        </select>
      </Field>
    </div>
  );
}

/* ---- generic repeating-row helpers ---- */
function RowHead({ n, onDelete }) {
  return (
    <div className="rowhead">
      <span className="rownum">#{String(n).padStart(2, "0")}</span>
      <button className="delbtn" onClick={onDelete} aria-label="Delete row"><Icon name="trash" size={15} /></button>
    </div>
  );
}
function EmptyRows({ icon, title, text }) {
  return (
    <div className="empty">
      <div className="ico"><Icon name={icon} size={24} /></div>
      <h3>{title}</h3>
      <p>{text}</p>
    </div>
  );
}

/* ---- Tab 2: STRATA / VÄLIMÄÄRANG ---- */
function GeosTab({ rows, update, remove, add }) {
  return (
    <div>
      {rows.length === 0
        ? <EmptyRows icon="layers" title="Kihte pole määratud" text="Lisa esimene kiht, et kirjeldada pinnase ja materjali profiili." />
        : <div className="list">
            {rows.map((r, i) => {
              const f = r.fieldMat ? getFieldMat(r.fieldMat) : null;
              return (
              <div className={"datarow" + (f ? " mat" : "")} key={i} style={f ? { "--matcol": f.hex } : undefined}>
                <RowHead n={i + 1} onDelete={() => remove(i)} />
                <div className="grid2" style={{ marginBottom: 12 }}>
                  <Field className="sm" label="Lael (m)" ags="GEOL_TOP">
                    <input className="input mono" inputMode="decimal" value={r.top} onChange={(e) => update(i, "top", e.target.value)} />
                  </Field>
                  <Field className="sm" label="Põhi (m)" ags="GEOL_BASE">
                    <input className="input mono" inputMode="decimal" value={r.base} onChange={(e) => update(i, "base", e.target.value)} />
                  </Field>
                </div>
                <Field className="sm" label="Materjali põhitüüp" ags="GEOL_LEG">
                  <div style={{ marginBottom: 12 }}>
                    <FieldMatField value={r.fieldMat} onChange={(v) => update(i, "fieldMat", v)} />
                  </div>
                </Field>
                <Field className="sm" label="Kirjeldus" ags="GEOL_DESC">
                  <textarea className="input mono" style={{ height: 72, padding: "10px 12px", lineHeight: 1.45, resize: "none" }}
                    value={r.desc} onChange={(e) => update(i, "desc", e.target.value)} />
                </Field>
              </div>
              );
            })}
          </div>}
      <button className="addbtn" onClick={add} style={{ marginTop: 12 }}><Icon name="plus" size={17} /> Lisa kiht</button>
    </div>
  );
}

/* ---- Tab 3: SAMPLES ---- */
function SampTab({ rows, update, remove, add }) {
  return (
    <div>
      {rows.length === 0
        ? <EmptyRows icon="flask" title="No samples recorded" text="Log driven tubes, bulk and water samples taken from this hole." />
        : <div className="list">
            {rows.map((r, i) => (
              <div className="datarow" key={i}>
                <RowHead n={i + 1} onDelete={() => remove(i)} />
                <div className="grid2" style={{ marginBottom: 12 }}>
                  <Field className="sm" label="Top (m)" ags="SAMP_TOP">
                    <input className="input mono" inputMode="decimal" value={r.top} onChange={(e) => update(i, "top", e.target.value)} />
                  </Field>
                  <Field className="sm" label="Base (m)" ags="SAMP_BASE">
                    <input className="input mono" inputMode="decimal" value={r.base} onChange={(e) => update(i, "base", e.target.value)} />
                  </Field>
                </div>
                <div className="grid2">
                  <Field className="sm" label="Reference" ags="SAMP_REF">
                    <input className="input mono" value={r.ref} onChange={(e) => update(i, "ref", e.target.value)} />
                  </Field>
                  <Field className="sm" label="Type" ags="SAMP_TYPE">
                    <select className="select" value={r.type} onChange={(e) => update(i, "type", e.target.value)}>
                      {SAMPLE_TYPES.map(([c, n]) => <option key={c} value={c}>{n}</option>)}
                      {!SAMPLE_TYPES.some(([c]) => c === r.type) && r.type && <option value={r.type}>{r.type}</option>}
                    </select>
                  </Field>
                </div>
              </div>
            ))}
          </div>}
      <button className="addbtn" onClick={add} style={{ marginTop: 12 }}><Icon name="plus" size={17} /> Add sample</button>
    </div>
  );
}

/* ---- Tab 4: SPT ---- */
function IsptTab({ rows, update, remove, add }) {
  return (
    <div>
      {rows.length === 0
        ? <EmptyRows icon="activity" title="No SPT results" text="Record standard penetration test depths and N-values as you drive." />
        : <div className="list">
            {rows.map((r, i) => (
              <div className="datarow" key={i}>
                <RowHead n={i + 1} onDelete={() => remove(i)} />
                <div className="grid2" style={{ marginBottom: 12 }}>
                  <Field className="sm" label="Depth (m)" ags="ISPT_TOP">
                    <input className="input mono" inputMode="decimal" value={r.depth} onChange={(e) => update(i, "depth", e.target.value)} />
                  </Field>
                  <Field className="sm" label="N-value" ags="ISPT_NVAL">
                    <input className="input mono" inputMode="numeric" value={r.n} onChange={(e) => update(i, "n", e.target.value)} />
                  </Field>
                </div>
                <Field className="sm" label="Report ref" ags="ISPT_REP">
                  <input className="input mono" value={r.ref} onChange={(e) => update(i, "ref", e.target.value)} />
                </Field>
              </div>
            ))}
          </div>}
      <button className="addbtn" onClick={add} style={{ marginTop: 12 }}><Icon name="plus" size={17} /> Add SPT</button>
    </div>
  );
}

/* ---- Tab 5: PHOTOS (real camera / upload, stored in IndexedDB) ---- */
function PhotoTab({ photos, onAdd, onRemove }) {
  const inputRef = useRef(null);
  const [busy, setBusy] = useState(false);
  const onFile = async (e) => {
    const f = e.target.files && e.target.files[0];
    e.target.value = "";
    if (!f) return;
    setBusy(true);
    try {
      const url = await RPStore.fileToDataUrl(f, 1400);
      await onAdd(url);
    } catch (err) { /* unreadable file */ }
    setBusy(false);
  };
  return (
    <div>
      {photos.length === 0
        ? <EmptyRows icon="image" title="No photos yet" text="Capture arisings, exposures and sample tins. Tap below to add." />
        : <div className="photogrid">
            {photos.map((ph, i) => {
              const isReal = ph && typeof ph === "object" && ph.pid;
              const url = isReal ? RPStore.photoUrl(ph.pid) : null;
              return (
                <div key={i} className={"photo" + (url ? " real" : "")}>
                  {url
                    ? <img src={url} alt={ph.name || ""} loading="lazy" />
                    : <div className="stripes"></div>}
                  <button type="button" className="photo-del" aria-label="Kustuta foto" onClick={() => onRemove(i)}>
                    <Icon name="x" size={13} stroke={2.6} />
                  </button>
                  <div className="cap">{typeof ph === "string" ? ph : ph.name}</div>
                </div>
              );
            })}
          </div>}
      <button className="addbtn" onClick={() => inputRef.current && inputRef.current.click()} disabled={busy} style={{ marginTop: 12, height: 56 }}>
        <Icon name="camera" size={19} /> {busy ? "Salvestan…" : "Take photo / Upload"}
      </button>
      <input ref={inputRef} type="file" accept="image/*" capture="environment" style={{ display: "none" }} onChange={onFile} />
    </div>
  );
}

/* ---- Form shell ---- */
function BoreholeForm({ borehole, project, onBack, onSave }) {
  const [tab, setTab] = useState("loca");
  const isNew = !borehole.id;
  /* ID, type & coordinates are set up by the admin (import). Lock them for the
     field crew by default; an ad-hoc hole created in the field starts open. */
  const [locked, setLocked] = useState(!isNew);
  const [log, setLog] = useState(() => {
    const l = logFor(borehole.id);
    /* new hole: suggest an ID from its type (prefix + next free number) */
    if (isNew && !l.loca.id) {
      l.loca.type = borehole.type || l.loca.type || "PA";
      l.loca.id = suggestBoreholeId(project.id, l.loca.type);
    }
    /* prefill position from the imported site plan (borehole record carries
       lat/lon from GPX/TXT import) when the log has no coordinates yet */
    const hasEN = parseFloat(l.loca.east) > 0 && parseFloat(l.loca.north) > 0;
    if (!hasEN && borehole.lat != null && borehole.lon != null) {
      const le = RPStore.wgsToLest(borehole.lat, borehole.lon);
      l.loca.east = le.y.toFixed(2);
      l.loca.north = le.x.toFixed(2);
      l.loca.lat = borehole.lat;
      l.loca.lon = borehole.lon;
      if (!l.loca.posSource) l.loca.posSource = "plan";
    }
    return l;
  });
  const scrollRef = useRef(null);

  const setLoca = (k, v) => setLog((s) => ({ ...s, loca: { ...s.loca, [k]: v } }));
  /* changing the type re-prefixes the ID (number kept). For an existing,
     already-named hole we leave the ID alone — renaming would re-key it. */
  const changeType = (t) => setLog((s) => {
    const loca = { ...s.loca, type: t };
    if (isNew) loca.id = reTypeId(s.loca.id, t) || suggestBoreholeId(project.id, t);
    return { ...s, loca };
  });
  const editRows = (key) => ({
    update: (i, k, v) => setLog((s) => { const a = [...s[key]]; a[i] = { ...a[i], [k]: v }; return { ...s, [key]: a }; }),
    remove: (i) => setLog((s) => ({ ...s, [key]: s[key].filter((_, j) => j !== i) })),
  });
  const addGeos = () => setLog((s) => ({ ...s, geos: [...s.geos, { top: s.geos.length ? s.geos[s.geos.length - 1].base : "0.00", base: "", fieldMat: "", mat: "", desc: "" }] }));
  const addSamp = () => setLog((s) => ({ ...s, samp: [...s.samp, { top: "", base: "", ref: "", type: "K" }] }));
  const addIspt = () => setLog((s) => ({ ...s, ispt: [...s.ispt, { depth: "", n: "", ref: "SPT" + (s.ispt.length + 1) }] }));

  const addPhoto = async (dataUrl) => {
    const name = (log.loca.id || "BH") + "_" + String(log.photos.length + 1).padStart(3, "0") + ".jpg";
    const pid = await RPStore.addPhoto(log.loca.id || "draft", dataUrl, name);
    setLog((s) => ({ ...s, photos: [...s.photos, { pid, name, ts: Date.now() }] }));
  };
  const removePhoto = (i) => {
    setLog((s) => {
      const ph = s.photos[i];
      if (ph && typeof ph === "object" && ph.pid) RPStore.deletePhoto(ph.pid);
      return { ...s, photos: s.photos.filter((_, j) => j !== i) };
    });
  };

  const doSave = async () => {
    if (!log.loca.id.trim()) {
      setTab("loca");
      onSave("Sisesta enne salvestamist puuraugu ID", true);
      return;
    }
    await RPStore.saveBoreholeLog(project.id, log);
    onSave("Salvestatud · " + log.loca.id.trim());
  };

  useEffect(() => { if (scrollRef.current) scrollRef.current.scrollTop = 0; }, [tab]);

  const counts = { geos: log.geos.length, samp: log.samp.length, ispt: log.ispt.length, photos: log.photos.length };

  return (
    <div className="screen fade-in">
      <div className="appbar">
        <button className="iconbtn" onClick={onBack} aria-label="Back"><Icon name="back" size={22} /></button>
        <div className="grow">
          <h1 className="mono" style={{ fontSize: 16 }}>{log.loca.id || "New borehole"}</h1>
          <div className="sub">{project.code}</div>
        </div>
        <span className={"badge " + (borehole.status === "Complete" ? "green" : "amber")}>
          <span className="dot" />{borehole.status || "Draft"}
        </span>
      </div>

      <div className="tabs">
        {TABS.map((t) => (
          <button key={t.key} className={"tab" + (tab === t.key ? " active" : "")} onClick={() => setTab(t.key)}>
            <span className="lbl">{t.lbl}{counts[t.key] ? <span style={{ color: "var(--accent-text)" }}> ·{counts[t.key]}</span> : null}</span>
            <span className="ags">{t.ags}</span>
          </button>
        ))}
      </div>

      <div className="scroll pad" ref={scrollRef}>
        {tab === "loca" && <LocaTab d={log.loca} set={setLoca} onType={changeType} locked={locked} onToggleLock={() => setLocked((v) => !v)} />}
        {tab === "geos" && <GeosTab rows={log.geos} {...editRows("geos")} add={addGeos} />}
        {tab === "samp" && <SampTab rows={log.samp} {...editRows("samp")} add={addSamp} />}
        {tab === "photos" && <PhotoTab photos={log.photos} onAdd={addPhoto} onRemove={removePhoto} />}
      </div>

      <div className="savebar">
        <div className="saveinfo">
          {counts.geos} strata · {counts.samp} samples
        </div>
        <button className="btn btn-primary" style={{ width: "auto", padding: "0 26px" }} onClick={doSave}>
          <Icon name="check" size={18} stroke={2.4} /> Save
        </button>
      </div>
    </div>
  );
}

Object.assign(window, { BoreholeForm });
