// tools.jsx — handy utilities: aviation weather (METAR/TAF) + unit converter.
// Exported to window. Weather goes through serve.py's /wx proxy (api.jsx).
const { useState: useTo, useEffect: useToFx } = React;

/* ============================== WEATHER (METAR/TAF) ============================== */
const WX_STATIONS = [
  { icao: "VTBD", label: "DMK" },   // Don Mueang
  { icao: "VTBS", label: "BKK" },   // Suvarnabhumi
];
const FLTCAT = {
  VFR: { c: "#1F8A5B", t: "VFR" }, MVFR: { c: "#1565C0", t: "MVFR" },
  IFR: { c: "#D11A2A", t: "IFR" }, LIFR: { c: "#9C27B0", t: "LIFR" },
};
const wxNum = (v) => (v == null || v === "" ? "—" : v);
const hpaToInhg = (h) => (h ? (h * 0.0295299830714).toFixed(2) : "—");
function cloudStr(clouds) {
  if (!clouds || !clouds.length) return "—";
  return clouds.map((c) => (c.cover || "") + (c.base != null ? String(Math.round(c.base / 100)).padStart(3, "0") : "")).join(" ");
}

function WxRow({ k, v, sub }) {
  return <div className="wx-kv"><span className="wx-k">{k}</span><span className="wx-v mono">{v}{sub && <i> {sub}</i>}</span></div>;
}

// ── rain / weather decode (METAR + TAF) ──────────────────────────────────────
const fmtZ = (e) => { if (!e) return "—"; const d = new Date(e * 1000); return String(d.getUTCHours()).padStart(2, "0") + String(d.getUTCMinutes()).padStart(2, "0") + "Z"; };
// Decode a wx group string ("-TSRA", "SHRA", "BR"…) → readable rain info.
function decodeWx(s) {
  if (!s) return null;
  const up = s.toUpperCase();
  const storm = /TS/.test(up);
  const rain = storm || /(RA|SH|DZ|GR|GS|PL)/.test(up);
  const heavy = up.indexOf("+") >= 0, light = up.indexOf("-") >= 0 && !heavy;
  let label;
  if (storm) label = /RA/.test(up) ? "ฝนฟ้าคะนอง" : "ฟ้าคะนอง";
  else if (/SH/.test(up)) label = "ฝนซู่";
  else if (/RA/.test(up)) label = "ฝน";
  else if (/DZ/.test(up)) label = "ฝนละออง";
  else if (/GR|GS/.test(up)) label = "ลูกเห็บ";
  else if (/FG/.test(up)) label = "หมอก";
  else if (/BR|HZ/.test(up)) label = "ฟ้าหลัว";
  else label = s;
  const inten = heavy ? " (หนัก)" : light ? " (เล็กน้อย)" : "";
  if (/VC/.test(up)) label += " ใกล้เคียง";
  return { rain, storm, heavy, label: (rain ? label + inten : label), raw: s };
}
const changeLabel = (p) => {
  const pre = p.prob ? "โอกาส " + p.prob + "% " : "";
  if (p.change === "TEMPO") return pre + "ช่วงสั้น";
  if (p.change === "BECMG") return pre + "เปลี่ยนเป็น";
  if (p.change === "FM" || p.change === "FROM") return pre + "ตั้งแต่";
  return pre || "ทั่วไป";
};
// Build a glanceable rain outlook from the METAR (now) + TAF (forecast).
function rainSummary(taf, metar) {
  const nowWx = decodeWx(metar && metar.wxString);
  const periods = ((taf && taf.fcsts) || []).map((f) => ({ from: f.timeFrom, to: f.timeTo, change: f.fcstChange, prob: f.probability, wx: decodeWx(f.wxString) }));
  const wet = periods.filter((p) => p.wx && p.wx.rain);
  const anyStorm = wet.some((p) => p.wx.storm);
  let level = "dry", head;
  if (nowWx && nowWx.rain) { level = nowWx.storm ? "storm" : "rain"; head = "ตอนนี้: " + nowWx.label; }
  else if (wet.length) { level = anyStorm ? "storm" : "rain"; head = "คาดมี" + (anyStorm ? "พายุฝนฟ้าคะนอง" : "ฝน"); }
  else head = "ไม่มีฝนในพยากรณ์";
  const sub = wet.length
    ? wet.map((p) => changeLabel(p) + " " + fmtZ(p.from) + "–" + fmtZ(p.to) + " · " + p.wx.label).join("\n")
    : "ท้องฟ้าโปร่ง–มีเมฆบางส่วน" + (taf ? " · ถึง " + fmtZ(taf.validTimeTo) : "");
  return { level, head, sub, periods };
}
const RAIN_ICON = { storm: "⛈️", rain: "🌧️", dry: "☀️" };

function WeatherSheet({ open, onClose }) {
  const [station, setStation] = useTo("VTBD");
  const [st, setSt] = useTo({ loading: false, metar: [], taf: [], at: null, error: null });
  const ids = WX_STATIONS.map((s) => s.icao).join(",");
  const load = () => {
    setSt((s) => ({ ...s, loading: true, error: null }));
    Promise.all([fetchMetar(ids).catch(() => []), fetchTaf(ids).catch(() => [])])
      .then(([metar, taf]) => setSt({ loading: false, metar, taf, at: nowHM(), error: null }))
      .catch((e) => setSt((s) => ({ ...s, loading: false, error: String((e && e.message) || e) })));
  };
  useToFx(() => { if (open) load(); }, [open]);

  const m = (st.metar || []).find((x) => x.icaoId === station);
  const t = (st.taf || []).find((x) => x.icaoId === station);
  const cat = m && FLTCAT[m.fltCat];
  const rain = (m || t) ? rainSummary(t, m) : null;

  return (
    <Sheet open={open} onClose={onClose} title="Weather · METAR / TAF" full>
      <div className="wx-stations">
        {WX_STATIONS.map((s) => (
          <button key={s.icao} className={"wx-stbtn" + (station === s.icao ? " wx-stbtn--on" : "")} onClick={() => setStation(s.icao)}>
            <b>{s.label}</b><span className="mono">{s.icao}</span>
          </button>
        ))}
        <button className="wx-refresh" onClick={load} title="Refresh">
          <Ic.sync width="16" height="16" />{st.loading ? "…" : (st.at ? st.at : "Load")}
        </button>
      </div>

      {st.error && <div className="wx-err"><Ic.warn width="15" height="15" />ดึงอากาศไม่ได้ — {st.error}</div>}
      {st.loading && !m && <div className="wx-load">Loading weather…</div>}

      {m && (
        <div className="wx-card">
          <div className="wx-head">
            <div className="wx-name">{m.name || station}</div>
            {cat && <span className="wx-cat" style={{ "--cc": cat.c }}>{cat.t}</span>}
          </div>
          <div className="wx-raw mono">{m.rawOb || "—"}</div>
          <div className="wx-grid">
            <WxRow k="Wind" v={m.wdir === 0 && m.wspd === 0 ? "CALM" : `${wxNum(m.wdir)}° / ${wxNum(m.wspd)}`} sub={m.wgst ? `G${m.wgst} kt` : "kt"} />
            <WxRow k="Visibility" v={wxNum(m.visib)} sub="SM" />
            <WxRow k="Temp / Dew" v={`${wxNum(m.temp)}° / ${wxNum(m.dewp)}°`} sub="C" />
            <WxRow k="QNH" v={wxNum(m.altim)} sub={`hPa · ${hpaToInhg(m.altim)}"`} />
            <WxRow k="Clouds" v={cloudStr(m.clouds)} />
            <WxRow k="Weather" v={m.wxString || "—"} />
          </div>
          <div className="wx-obs mono">Obs {m.reportTime ? m.reportTime.slice(11, 16) + "Z" : "—"}{m.fltCat ? " · " + m.fltCat : ""}</div>
        </div>
      )}

      {rain && (
        <div className={"wx-rain wx-rain--" + rain.level}>
          <span className="wx-rain-ic">{RAIN_ICON[rain.level]}</span>
          <div className="wx-rain-main">
            <div className="wx-rain-h">{rain.head}</div>
            {rain.sub && <div className="wx-rain-sub">{rain.sub}</div>}
          </div>
        </div>
      )}

      <div className="wx-taf">
        <div className="wx-taf-h">TAF · {station}</div>
        <div className="wx-raw mono">{t ? (t.rawTAF || "—") : (st.loading ? "…" : "—")}</div>
        {rain && rain.periods.length > 0 && (
          <div className="taf-periods">
            {rain.periods.map((p, i) => {
              const lv = p.wx ? (p.wx.storm ? "storm" : p.wx.rain ? "rain" : "dry") : "dry";
              return (
                <div key={i} className={"taf-p taf-p--" + lv}>
                  <span className="taf-p-time mono">{fmtZ(p.from)}–{fmtZ(p.to)}</span>
                  <span className="taf-p-type">{changeLabel(p)}</span>
                  <span className="taf-p-wx">{RAIN_ICON[lv]} {p.wx ? p.wx.label : "ไม่มีฝน"}</span>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <div className="wx-note"><Ic.warn width="14" height="14" /><span>ข้อมูลจาก aviationweather.gov · อ้างอิงประกอบ ไม่ใช่เอกสารวางแผนการบินทางการ</span></div>
    </Sheet>
  );
}

/* ============================== UNIT CONVERTER ============================== */
// factor = how many BASE units in 1 of this unit (base = the unit with factor 1).
const CONV = {
  Torque: [["N·m", 1], ["ft·lb", 1.3558179], ["in·lb", 0.11298483], ["kgf·m", 9.80665]],
  Pressure: [["psi", 1], ["bar", 14.5037738], ["kPa", 0.14503774], ["hPa", 0.014503774], ["inHg", 0.49115413]],
  Length: [["mm", 1], ["cm", 10], ["in", 25.4], ["ft", 304.8], ["m", 1000]],
  Volume: [["L", 1], ["US gal", 3.78541178], ["Imp gal", 4.54609], ["mL", 0.001]],
  Mass: [["kg", 1], ["lb", 0.45359237], ["g", 0.001], ["oz", 0.0283495]],
};
const CONV_CATS = Object.keys(CONV).concat("Temp");

function fmtConv(n) {
  if (!isFinite(n)) return "—";
  const a = Math.abs(n);
  if (a !== 0 && (a < 0.001 || a >= 1e6)) return n.toExponential(3);
  let s = n.toFixed(a >= 100 ? 2 : a >= 1 ? 3 : 5);
  if (s.indexOf(".") >= 0) s = s.replace(/0+$/, "").replace(/\.$/, "");
  return s;
}
function convUnit(n, cat, from, to) {
  const u = CONV[cat]; const ff = (u.find((x) => x[0] === from) || [0, 1])[1]; const tf = (u.find((x) => x[0] === to) || [0, 1])[1];
  return (n * ff) / tf;
}
function tempConv(n, from, to) {
  const c = from === "°C" ? n : from === "°F" ? (n - 32) * 5 / 9 : n - 273.15;
  return to === "°C" ? c : to === "°F" ? c * 9 / 5 + 32 : c + 273.15;
}

function ConverterSheet({ open, onClose }) {
  const [cat, setCat] = useTo("Torque");
  const [val, setVal] = useTo("100");
  const units = cat === "Temp" ? ["°C", "°F", "K"] : CONV[cat].map((u) => u[0]);
  const [from, setFrom] = useTo("N·m");
  useToFx(() => { setFrom(units[0]); }, [cat]);
  const n = parseFloat(val);
  const valid = !isNaN(n) && units.includes(from);
  const rows = units.map((u) => ({ u, v: !valid ? "—" : (cat === "Temp" ? tempConv(n, from, u) : convUnit(n, cat, from, u)) }));

  return (
    <Sheet open={open} onClose={onClose} title="Unit Converter" full>
      <div className="cv-cats">
        {CONV_CATS.map((c) => <button key={c} className={"cv-cat" + (cat === c ? " cv-cat--on" : "")} onClick={() => setCat(c)}>{c}</button>)}
      </div>
      <div className="cv-input">
        <input className="inp inp--mono cv-val" inputMode="decimal" value={val} onChange={(e) => setVal(e.target.value)} onFocus={(e) => e.target.select()} />
        <div className="cv-fromrow">
          {units.map((u) => <button key={u} className={"cv-unit" + (from === u ? " cv-unit--on" : "")} onClick={() => setFrom(u)}>{u}</button>)}
        </div>
      </div>
      <div className="cv-results">
        {rows.map((r) => (
          <div key={r.u} className={"cv-row" + (r.u === from ? " cv-row--from" : "")}>
            <span className="cv-runit">{r.u}</span>
            <span className="cv-rval mono">{typeof r.v === "number" ? fmtConv(r.v) : r.v}</span>
          </div>
        ))}
      </div>
      <div className="wx-note"><Ic.swap width="14" height="14" /><span>พิมพ์ค่า + เลือกหน่วยต้นทาง → แปลงทุกหน่วยให้ทันที · torque/แรงดัน/ระยะ/ปริมาตร/มวล/อุณหภูมิ</span></div>
    </Sheet>
  );
}

Object.assign(window, { WeatherSheet, ConverterSheet, WX_STATIONS, CONV });
