/* Root App — wires inputs ↔ engine ↔ results, owns sharing & PDF actions */

const { useState, useEffect, useMemo, useRef } = React;

// Pulls live USD/AMD from the same source as the site's currency ticker, with the
// same localStorage cache (6h TTL). Returns the AMD-per-USD rate as a number.
const FX_API_KEY    = "f50027e2feddbf7bf054a8c4";
const FX_CACHE_KEY  = "sicosa_fx_v1";
const FX_TTL_MS     = 6 * 60 * 60 * 1000;
async function fetchLiveFxAmd({ force = false } = {}) {
  if (!force) {
    try {
      const raw = localStorage.getItem(FX_CACHE_KEY);
      if (raw) {
        const c = JSON.parse(raw);
        if (c && c.rates && Number.isFinite(c.rates.AMD) && Date.now() - c.ts < FX_TTL_MS) {
          return c.rates.AMD;
        }
      }
    } catch {}
  }
  const res = await fetch(`https://v6.exchangerate-api.com/v6/${FX_API_KEY}/latest/USD`);
  if (!res.ok) throw new Error("fx fetch failed");
  const data = await res.json();
  if (data.result !== "success") throw new Error("fx api error");
  try { localStorage.setItem(FX_CACHE_KEY, JSON.stringify({ ts: Date.now(), rates: data.conversion_rates })); } catch {}
  return data.conversion_rates.AMD;
}

function App() {
  const E = window.SicosaEngine;

  // Initial state: shareable URL hash > defaults
  const [inputs, setInputs] = useState(() => {
    const shared = window.Share.hydrate();
    const fuel = shared && shared.fuelType || "diesel";
    const base = E.defaultsFor(fuel);
    const merged = { ...base, ...(shared || {}) };
    // Back-compat: older shared links may not include customs duty
    if (!Number.isFinite(merged.customsDutyAmdPerTon)) merged.customsDutyAmdPerTon = 0;
    return merged;
  });
  const [toast, setToast] = useState(null);
  // Track whether density has been manually edited; if so, don't auto-fill on fuel change
  const densityTouched = useRef(false);
  // Track whether fxRate has been manually edited; if so, don't override with live rate
  const fxTouched = useRef(false);

  const set = (patch) => {
    setInputs((s) => {
      const next = { ...s, ...patch };
      // Track density edits
      if ("density" in patch) densityTouched.current = true;
      // Track fxRate edits (only user edits — auto-fill uses setInputs directly)
      if ("fxRate" in patch) fxTouched.current = true;
      // Auto-fill density on fuel change (only if user hasn't manually edited)
      if ("fuelType" in patch) {
        const fuel = E.FUELS[patch.fuelType];
        if (fuel) {
          if (!densityTouched.current || s.density === E.FUELS[s.fuelType]?.density) {
            next.density = fuel.density;
            densityTouched.current = false;
          }
        }
      }
      return next;
    });
  };

  // Compute results — engine + errors
  const { result, errors } = useMemo(() => {
    const errs = E.validate(inputs);
    if (Object.keys(errs).length === 0) {
      try {
        return { result: E.calculate(inputs), errors: {} };
      } catch (e) {
        return { result: null, errors: { _engine: e.message } };
      }
    }
    return { result: null, errors: errs };
  }, [inputs]);

  // Note: URL hash is intentionally NOT updated on every input change.
  // It is only written when the user clicks "Copy Link" (window.Share.copyShareLink).
  // This keeps fresh opens clean — no stale densities or FX rates carry over from
  // previous sessions. Inbound share links (?…#q=…) still hydrate correctly.

  // Lucide icon refresh on every render
  useEffect(() => {
    if (window.lucide && window.lucide.createIcons) window.lucide.createIcons();
  });

  // Auto-fetch live USD/AMD rate from the same source as the site ticker, then apply +0.5%.
  // User-edited rates win (fxTouched). Shared URL (?fxRate=…) also wins (treated as touched).
  useEffect(() => {
    const shared = window.Share.hydrate();
    if (shared && Number.isFinite(shared.fxRate)) {
      fxTouched.current = true;
      return;
    }
    fetchLiveFxAmd().then((amd) => {
      if (!Number.isFinite(amd) || fxTouched.current) return;
      const adjusted = Math.round(amd * 1.005 * 100) / 100; // +0.5%, 2 decimals
      setInputs((s) => ({ ...s, fxRate: adjusted }));
    }).catch(() => { /* silent — keep default */ });
  }, []);

  // Toast auto-dismiss
  useEffect(() => {
    if (!toast) return;
    const id = setTimeout(() => setToast(null), 2400);
    return () => clearTimeout(id);
  }, [toast]);

  // Actions
  const onCopyLink = async () => {
    const r = await window.Share.copyShareLink(inputs);
    setToast(r.ok ? "Link copied — paste anywhere to share" : "Link ready in address bar");
  };
  const onExportPDF = () => {
    setTimeout(() => window.exportPDF(), 40);
  };
  const onReset = () => {
    densityTouched.current = false;
    fxTouched.current = false;
    // Clear any shared-link hash so refresh won't restore old values
    try { window.history.replaceState(null, "", window.location.pathname + window.location.search); } catch {}
    setInputs(E.defaultsFor(inputs.fuelType));
    setToast("Reset to defaults for " + E.FUELS[inputs.fuelType].label);
    // Force-pull a fresh live rate after reset (bypass localStorage cache)
    fetchLiveFxAmd({ force: true }).then((amd) => {
      if (!Number.isFinite(amd) || fxTouched.current) return;
      const adjusted = Math.round(amd * 1.005 * 100) / 100;
      setInputs((s) => ({ ...s, fxRate: adjusted }));
    }).catch(() => {});
  };

  // For results panel — if validation is failing, show last good or empty
  const safeResult = result;

  return (
    <div>
      <AppHeader onCopyLink={onCopyLink} onExportPDF={onExportPDF} onReset={onReset} />

      <main className="canvas">
        <FuelSelector value={inputs.fuelType} onChange={(f) => set({ fuelType: f })} />

        <div className="dash">
          <div>
            <div className="card">
              <div className="card__head">
                <div>
                  <div className="card__title">Inputs</div>
                  <div className="card__sub">All fields editable · density auto-fills</div>
                </div>
              </div>
              <div className="card__body">
                <InputsForm inputs={inputs} set={set} errors={errors} />
              </div>
              {safeResult ? (
                <AdvancedPanel
                  result={safeResult}
                  includeFixedCosts={inputs.includeFixedCosts}
                  onToggleFixedCosts={() => set({ includeFixedCosts: !inputs.includeFixedCosts })}
                  customsDutyAmdPerTon={inputs.customsDutyAmdPerTon || 0}
                  onChangeCustomsDuty={(v) => set({ customsDutyAmdPerTon: v })}
                />
              ) : null}
            </div>
          </div>

          {safeResult ?
          <ResultsPanel result={safeResult} /> :

          <div className="card">
              <div className="card__body">
                <div style={{ padding: 24, color: "var(--status-error)", fontSize: 13 }}>
                  {Object.values(errors).join(" · ")}
                </div>
              </div>
            </div>
          }
        </div>
      </main>

      {/* Hidden print-only doc, visible only when printing / Save as PDF */}
      {safeResult ? <PrintDoc result={safeResult} /> : null}

      {toast ?
      <div className="toast">
          <i data-lucide="check"></i>
          {toast}
        </div> :
      null}
    </div>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);