/* ============================================================
   VKTR TCO — Vehicle Specifications / "My Library" vehicle overlay (V1.7)
   ------------------------------------------------------------
   Design (Notion: Roadmap — Vehicle Library, Routes & 3-Tier Access):
   - The built-in catalog (window.VEHICLES, from the Excel file) stays
     completely static. Per-user edits live as a sparse Firestore overlay
     (users/{uid}/customVehicles/{catalogId}), merged on top of the catalog
     default at lookup time -- never mutating window.VEHICLES itself.
   - Signed-in gated (tier 2), NOT apiAccess-gated (tier 3) -- this is plain
     Firestore CRUD, no paid/metered API call involved.
   - Guests (no sign-in) can still edit in-session -- same read path, just
     never written to Firestore, lost on reload. That's why the override
     cache lives in React state + a window mirror regardless of sign-in
     status, and only gains a Firestore listener once signed in.
   - window.findVeh() (data.jsx) is the single lookup point used everywhere
     in the engine -- this file only needs to keep window.__customVehicles
     in sync; findVeh() itself does the merge. No other call site changes.
   - Two doc shapes in customVehicles/{docId}:
       docId === a real catalog id  -> { isOverride: true, overrides: {...} }
       docId starts with "custom_"  -> { isNew: true, ...full vehicle fields }
   ============================================================ */

const CUSTOM_VEHICLE_ID_PREFIX = "custom_";

function newCustomVehicleId() {
  return `${CUSTOM_VEHICLE_ID_PREFIX}${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}

const CustomVehiclesContext = React.createContext({
  customVehicles: {},
  setOverride: () => {},
  resetOverride: () => {},
  addNewVehicle: () => {},
  deleteCustomVehicle: () => {},
  syncError: false,
});
function useCustomVehicles() { return React.useContext(CustomVehiclesContext); }

function CustomVehiclesProvider({ children }) {
  const { user } = useAuth();
  const [customVehicles, setCustomVehicles] = React.useState({});
  // v1.9.10: writeDoc()/resetOverride() below are optimistic and fire on
  // every keystroke (AffixInput has no debounce) -- an alert()-per-write on
  // failure, matching the pattern used elsewhere for explicit "Save"
  // actions, would spam the user mid-typing. Instead surface a single
  // sticky, non-blocking banner (rendered by VehicleSpecificationsPanel)
  // that clears itself the moment any write succeeds again.
  const [syncError, setSyncError] = React.useState(false);

  // window.__customVehicles mirrors this state for window.findVeh() (data.jsx),
  // a non-React function that must read it synchronously. Mirroring via a
  // useEffect runs AFTER commit -- one render behind any component that
  // calls findVeh() during its own render off the back of this same state
  // change, which silently shows stale values for exactly one interaction.
  // Instead every write below sets window.__customVehicles synchronously,
  // inside the same state updater, so a re-render triggered by this change
  // always sees the new value immediately.
  const applyCustomVehicles = (next) => {
    window.__customVehicles = next;
    setCustomVehicles(next);
  };

  // v1.8.7 (2026-07-19): depend on user?.uid (a stable primitive), not the
  // whole `user` object -- Firebase Auth hands onAuthStateChanged a NEW user
  // object reference on every ID token refresh (roughly hourly, sometimes
  // sooner) even for the same signed-in account. Depending on the object
  // itself re-fires this effect on every refresh, tearing down and
  // re-subscribing the Firestore listener -- during the gap before the new
  // listener's first snapshot arrives, window.__customVehicles is briefly
  // whatever it was left at, and any component re-rendering off an unrelated
  // state change in that window reads findVeh() against a listener that's
  // mid-resubscribe. For a "custom_"-prefixed vehicle (no static catalog
  // fallback), a snapshot gap here made getEvVehicle()/computeRitaseCycle()
  // intermittently see that vehicle as gone, flipping Annual Mileage between
  // computed and raw-input with no user action -- reported by Rija.
  const uid = user ? user.uid : null;
  React.useEffect(() => {
    if (!uid || typeof firebase === "undefined" || !firebase.apps.length) return;
    const unsub = firebase.firestore().collection("users").doc(uid).collection("customVehicles")
      .onSnapshot((snap) => {
        const next = {};
        snap.forEach((doc) => { next[doc.id] = doc.data(); });
        applyCustomVehicles(next);
      });
    return unsub;
  }, [uid]);

  // Signing out clears the in-memory cache (Firestore-backed data isn't
  // lost, just no longer loaded into this session) -- signing into a
  // different account shouldn't see the previous account's overrides even
  // for a moment.
  React.useEffect(() => {
    if (!uid) applyCustomVehicles({});
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [uid]);

  const writeDoc = (docId, data) => {
    applyCustomVehicles({ ...customVehicles, [docId]: data }); // optimistic, works for guests too
    if (user && typeof firebase !== "undefined" && firebase.apps.length) {
      firebase.firestore().collection("users").doc(user.uid).collection("customVehicles").doc(docId)
        .set(data, { merge: true }).then(() => setSyncError(false)).catch(() => setSyncError(true));
    }
  };

  const setOverride = (catalogId, field, value) => {
    const existing = customVehicles[catalogId];
    const overrides = { ...(existing && existing.overrides), [field]: value };
    writeDoc(catalogId, { isOverride: true, baseId: catalogId, overrides, updatedAt: Date.now() });
  };

  const resetOverride = (catalogId) => {
    const next = { ...customVehicles };
    delete next[catalogId];
    applyCustomVehicles(next);
    if (user && typeof firebase !== "undefined" && firebase.apps.length) {
      firebase.firestore().collection("users").doc(user.uid).collection("customVehicles").doc(catalogId)
        .delete().then(() => setSyncError(false)).catch(() => setSyncError(true));
    }
  };

  const addNewVehicle = (fields) => {
    const id = newCustomVehicleId();
    writeDoc(id, { isNew: true, createdAt: Date.now(), ...fields });
    return id;
  };

  const deleteCustomVehicle = (id) => resetOverride(id);

  // v1.7.5: restores a full doc shape as-is (either isOverride or isNew) --
  // used by the profile export/import "include custom vehicles" toggle
  // (app.jsx) to make a profile portable across accounts, since a plain
  // profile export only ever carried vehA/vehB/existingVehicleId as bare
  // catalog ids, silently unresolved on an account that never made that
  // custom vehicle. Same writeDoc path as every other write here, so it's
  // optimistic for guests and Firestore-persisted once signed in.
  const importCustomVehicle = (docId, data) => writeDoc(docId, data);

  return (
    <CustomVehiclesContext.Provider value={{ customVehicles, setOverride, resetOverride, addNewVehicle, deleteCustomVehicle, importCustomVehicle, syncError }}>
      {children}
    </CustomVehiclesContext.Provider>
  );
}

// ---- Vehicle Specifications sub-tab (Screen 2) ----
const VEHICLE_SPEC_FIELDS = [
  { key: "gvw", en: "GVW", id_: "GVW", suffix: "kg", type: "int" },
  { key: "payload", en: "Payload", id_: "Payload", suffix: "kg", type: "int", nullable: true },
  { key: "price", en: "Unit Price", id_: "Harga Unit", prefix: "Rp", type: "int" },
  { key: "power", en: "Power", id_: "Daya", suffix: "kW", type: "int" },
  { key: "energyNum", en: "Energy Consumption", id_: "Konsumsi Energi", type: "decimal" }, // unit depends on powertrain, shown separately
  { key: "batteryKwh", en: "Battery Capacity", id_: "Kapasitas Baterai", suffix: "kWh", type: "decimal", evOnly: true },
  // v1.7.5 -- 2 of the platform's 4 SAW/competitive-benchmark scoring
  // criteria (see V6 "Summary" sheet: Payload 33.5% / Max Torque at Wheel
  // 28.7% / Curb Weight 24.2% / Power-to-Weight 13.7%), previously tracked
  // in the source Excel but never exposed here. Payload's already above;
  // Power-to-Weight is power/curbWeight, derived, not its own stored field.
  { key: "curbWeight", en: "Curb Weight", id_: "Berat Kosong", suffix: "kg", type: "int", nullable: true },
  { key: "torqueAtWheelNm", en: "Max Torque at Wheel", id_: "Torsi Maks di Roda", suffix: "N·m", type: "decimal", nullable: true },
  // v1.7.7 Wave 4 -- battery replacement timing (data.jsx vehicleCalc) is
  // now cycle-based (cyclesPerYear = annualKm / usable range per charge)
  // instead of a calendar %/year threshold; this is the per-vehicle
  // cycle-life rating that drives it. Blank = platform default of 4000
  // cycles applies (veh.batteryCycleLife ?? 4000, see data.jsx) -- not
  // backfilled across the whole catalog, so the field stays nullable.
  { key: "batteryCycleLife", en: "Battery Cycle Life Standard", id_: "Standar Siklus Baterai", suffix: "cycles", type: "int", evOnly: true, nullable: true, placeholder: "4000" },
];

function VehicleSpecEditor({ vehKey, s, set, lang }) {
  const { user } = useAuth();
  const { customVehicles, setOverride, resetOverride } = useCustomVehicles();
  const vehId = s[vehKey];
  const veh = findVeh(vehId);
  if (!veh) return null;
  const isCustomized = !!veh._customized;
  const custom = customVehicles[vehId];
  const isBrandNew = custom && custom.isNew;

  const energyUnit = veh.powertrain === "EV" ? "kWh/km" : "L/100km";

  const commit = (field, raw, type) => {
    let value = raw;
    if (type === "int") value = Math.max(0, Math.round(Number(raw) || 0));
    if (type === "decimal") value = Math.max(0, Number(raw) || 0);
    setOverride(vehId, field, value);
  };

  return (
    <div className="vehicle-spec-editor">
      <div className="vehicle-spec-header">
        <div>
          <Badge kind={veh.powertrain === "EV" ? "ev" : "ice"}>{veh.powertrain}</Badge>
          {veh.vktr && <Badge kind="vktr">VKTR</Badge>}
          <span className="vehicle-spec-name">{veh.brand} {veh.name}</span>
          {isCustomized && <Badge kind="warn">{tr(lang, "Customized", "Disesuaikan")}</Badge>}
          {isBrandNew && <Badge kind="info">{tr(lang, "Custom vehicle", "Kendaraan kustom")}</Badge>}
        </div>
        {isCustomized && (
          <button type="button" className="btn btn-ghost" style={{ fontSize: 12 }} onClick={() => resetOverride(vehId)}>
            ↺ {tr(lang, "Reset to catalog", "Reset ke katalog")}
          </button>
        )}
      </div>

      {!user && (
        <div className="vehicle-spec-guest-note">
          <Tr en="Not signed in — edits apply for this session only and won't be saved." id="Belum masuk — perubahan hanya berlaku untuk sesi ini dan tidak disimpan." />
        </div>
      )}

      <div className="vehicle-spec-grid">
        {VEHICLE_SPEC_FIELDS.filter(f => !f.evOnly || veh.powertrain === "EV").map((f) => (
          <Field key={f.key} en={f.en} id={f.id_}>
            <AffixInput
              value={f.key === "energyNum" ? fmt.num(veh.energyNum) : (veh[f.key] == null ? "" : fmt.num(veh[f.key]))}
              prefix={f.prefix}
              suffix={f.key === "energyNum" ? energyUnit : f.suffix}
              placeholder={f.placeholder}
              onChange={(v) => commit(f.key, v.replace(/[^\d.]/g, ""), f.type)}
            />
          </Field>
        ))}
      </div>
    </div>
  );
}

function VehicleSpecificationsPanel({ s, set }) {
  const { lang } = useLang();
  const { syncError } = useCustomVehicles();
  const [addOpen, setAddOpen] = React.useState(false);
  return (
    <div className="vs-grid">
      {syncError && (
        <div className="vehicle-spec-guest-note" style={{ gridColumn: "1 / -1" }}>
          <Tr en="Your vehicle edits aren't syncing right now — they're kept for this session, but check your connection so they're not lost on reload."
              id="Perubahan kendaraan Anda tidak tersinkron saat ini — perubahan tetap berlaku untuk sesi ini, tetapi periksa koneksi Anda agar tidak hilang saat memuat ulang." />
        </div>
      )}
      <VehicleSpecEditor vehKey="vehA" s={s} set={set} lang={lang} />
      <div className="vs-divider"><span>VS</span></div>
      <VehicleSpecEditor vehKey="vehB" s={s} set={set} lang={lang} />
      <div className="vs-add-row">
        <button type="button" className="btn btn-ghost" onClick={() => setAddOpen(true)}>
          + <Tr en="Add New Vehicle" id="Tambah Kendaraan Baru" />
        </button>
      </div>
      {addOpen && <AddVehicleModal onClose={() => setAddOpen(false)} />}
    </div>
  );
}

// ---- Add New Vehicle (v1.7.5) — explicit "build a custom vehicle from
// scratch" flow, wiring up addNewVehicle() (already built, never had a UI
// trigger). 2-step: pick Class + Powertrain first, then a form pre-filled
// with that combination's catalog median (GVW/payload/price/power/energy/
// curbWeight/torqueAtWheelNm) so the user only really has to type the
// handful of fields that are genuinely vehicle-specific -- brand, name,
// and whatever they want to correct from the pre-filled median. A brand-
// new custom vehicle has no PM_SCHEDULE entry, but data.jsx's
// maintCostForYear() already falls back to PM_SEGMENT_DEFAULT[segment]
// automatically when one is missing -- no pmKey needed here.
const VEHICLE_SEGMENTS = ["LDT", "MDT", "HDT", "BUS", "TH", "VAN", "Double Cabin", "Pickup"];

function medianOf(values) {
  const vals = values.filter((v) => v != null && !isNaN(v)).sort((a, b) => a - b);
  if (!vals.length) return null;
  const mid = Math.floor(vals.length / 2);
  return vals.length % 2 ? vals[mid] : Math.round((vals[mid - 1] + vals[mid]) / 2);
}

function computeSegmentDefaults(segment, powertrain) {
  const matches = (window.VEHICLES || []).filter((v) => v.segment === segment && v.powertrain === powertrain);
  return {
    matchCount: matches.length,
    gvw: medianOf(matches.map((v) => v.gvw)) || 0,
    payload: medianOf(matches.map((v) => v.payload)),
    price: medianOf(matches.map((v) => v.price)) || 0,
    power: medianOf(matches.map((v) => v.power)) || 0,
    energyNum: medianOf(matches.map((v) => v.energyNum)) || 0,
    batteryKwh: medianOf(matches.map((v) => v.batteryKwh)),
    curbWeight: medianOf(matches.map((v) => v.curbWeight)),
    torqueAtWheelNm: medianOf(matches.map((v) => v.torqueAtWheelNm)),
    adblue: powertrain === "ICE" && matches.filter((v) => v.adblue).length > matches.length / 2,
  };
}

function AddVehicleModal({ onClose }) {
  const { lang } = useLang();
  const { addNewVehicle } = useCustomVehicles();
  const [segment, setSegment] = React.useState("");
  const [powertrain, setPowertrain] = React.useState("");
  const [fields, setFields] = React.useState(null);
  const [matchCount, setMatchCount] = React.useState(0);

  const startForm = () => {
    if (!segment || !powertrain) return;
    const d = computeSegmentDefaults(segment, powertrain);
    setMatchCount(d.matchCount);
    setFields({
      brand: "", name: "", segment, powertrain, vktr: false,
      gvw: d.gvw, payload: d.payload, price: d.price, power: d.power,
      energyNum: d.energyNum, batteryKwh: powertrain === "EV" ? (d.batteryKwh || 0) : null,
      curbWeight: d.curbWeight, torqueAtWheelNm: d.torqueAtWheelNm, adblue: d.adblue,
    });
  };

  const setField = (key, val) => setFields((prev) => ({ ...prev, [key]: val }));

  const commit = () => {
    if (!fields.brand.trim() || !fields.name.trim()) {
      alert(tr(lang, "Brand and name are required.", "Merek dan nama wajib diisi."));
      return;
    }
    const energyUnit = fields.powertrain === "EV" ? "kWh/km" : "L/100km";
    addNewVehicle({
      ...fields,
      energy: `${fields.energyNum} ${energyUnit}`,
    });
    onClose();
  };

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-panel" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 480 }}>
        <div className="modal-head">
          <h2>+ <Tr en="Add New Vehicle" id="Tambah Kendaraan Baru" /></h2>
          <button type="button" className="modal-close" onClick={onClose}>✕</button>
        </div>

        {!fields ? (
          <>
            <div className="grid-2">
              <Field en="Vehicle Class" id="Kelas Kendaraan">
                <Select value={segment} onChange={setSegment} placeholder={tr(lang, "Choose class…", "Pilih kelas…")}
                  options={VEHICLE_SEGMENTS.map((s) => ({ value: s, label: s }))} />
              </Field>
              <Field en="Powertrain" id="Jenis Penggerak">
                <Select value={powertrain} onChange={setPowertrain} placeholder={tr(lang, "Choose powertrain…", "Pilih penggerak…")}
                  options={[{ value: "EV", label: "EV" }, { value: "ICE", label: "ICE" }]} />
              </Field>
            </div>
            <button type="button" className="btn btn-primary" style={{ marginTop: 16 }} disabled={!segment || !powertrain} onClick={startForm}>
              <Tr en="Continue" id="Lanjutkan" />
            </button>
          </>
        ) : (
          <>
            <p className="admin-panel-note">
              {matchCount > 0
                ? tr(lang, `Pre-filled from ${matchCount} catalog vehicle(s) in ${segment}/${powertrain} — adjust anything below.`,
                           `Diisi otomatis dari ${matchCount} kendaraan katalog di ${segment}/${powertrain} — sesuaikan yang mana pun di bawah.`)
                : tr(lang, "No catalog vehicles in this class/powertrain combination to base defaults on — fill in from scratch.",
                           "Tidak ada kendaraan katalog di kombinasi kelas/penggerak ini untuk dasar default — isi dari awal.")}
            </p>
            <div className="grid-2">
              <Field en="Brand" id="Merek" req>
                <input className="input" value={fields.brand} onChange={(e) => setField("brand", e.target.value)} />
              </Field>
              <Field en="Model Name" id="Nama Model" req>
                <input className="input" value={fields.name} onChange={(e) => setField("name", e.target.value)} />
              </Field>
              <Field en="GVW" id="GVW">
                <AffixInput suffix="kg" value={String(fields.gvw)} onChange={(v) => setField("gvw", Math.max(0, Math.round(Number(v.replace(/\D/g, "")) || 0)))} />
              </Field>
              <Field en="Payload" id="Payload">
                <AffixInput suffix="kg" value={fields.payload == null ? "" : String(fields.payload)} onChange={(v) => setField("payload", v ? Math.max(0, Math.round(Number(v.replace(/\D/g, "")) || 0)) : null)} />
              </Field>
              <Field en="Unit Price" id="Harga Unit">
                <AffixInput prefix="Rp" value={String(fields.price)} onChange={(v) => setField("price", Math.max(0, Math.round(Number(v.replace(/\D/g, "")) || 0)))} />
              </Field>
              <Field en="Power" id="Daya">
                <AffixInput suffix="kW" value={String(fields.power)} onChange={(v) => setField("power", Math.max(0, Math.round(Number(v.replace(/\D/g, "")) || 0)))} />
              </Field>
              <Field en="Energy Consumption" id="Konsumsi Energi">
                <AffixInput suffix={fields.powertrain === "EV" ? "kWh/km" : "L/100km"} value={String(fields.energyNum)} onChange={(v) => setField("energyNum", Math.max(0, Number(v.replace(/[^\d.]/g, "")) || 0))} />
              </Field>
              {fields.powertrain === "EV" && (
                <Field en="Battery Capacity" id="Kapasitas Baterai">
                  <AffixInput suffix="kWh" value={String(fields.batteryKwh)} onChange={(v) => setField("batteryKwh", Math.max(0, Number(v.replace(/[^\d.]/g, "")) || 0))} />
                </Field>
              )}
              <Field en="Curb Weight" id="Berat Kosong" opt>
                <AffixInput suffix="kg" value={fields.curbWeight == null ? "" : String(fields.curbWeight)} onChange={(v) => setField("curbWeight", v ? Math.max(0, Math.round(Number(v.replace(/\D/g, "")) || 0)) : null)} />
              </Field>
              <Field en="Max Torque at Wheel" id="Torsi Maks di Roda" opt>
                <AffixInput suffix="N·m" value={fields.torqueAtWheelNm == null ? "" : String(fields.torqueAtWheelNm)} onChange={(v) => setField("torqueAtWheelNm", v ? Math.max(0, Number(v.replace(/[^\d.]/g, "")) || 0) : null)} />
              </Field>
            </div>
            {fields.powertrain === "ICE" && (
              <label style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 12, fontSize: 13, cursor: "pointer" }}>
                <input type="checkbox" checked={!!fields.adblue} onChange={(e) => setField("adblue", e.target.checked)} />
                <Tr en="Requires AdBlue (SCR)" id="Memerlukan AdBlue (SCR)" />
              </label>
            )}
            <div style={{ display: "flex", gap: 8, marginTop: 16 }}>
              <button type="button" className="btn btn-primary" onClick={commit}>
                <Tr en="Save vehicle" id="Simpan kendaraan" />
              </button>
              <button type="button" className="btn btn-ghost" onClick={() => setFields(null)}>
                <Tr en="← Back" id="← Kembali" />
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { CustomVehiclesProvider, useCustomVehicles, VehicleSpecificationsPanel, newCustomVehicleId });
