// app.jsx — shell: header, footer, routing, tweaks. Mounts the app.

const LOGO_SRC = "data:image/svg+xml," + encodeURIComponent(
  "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>" +
  "<rect width='32' height='32' rx='9' fill='#1d1d1f'/>" +
  "<g fill='#ffffff'>" +
  "<rect x='7' y='7' width='6' height='6' rx='1.6'/>" +
  "<rect x='19' y='7' width='6' height='6' rx='1.6'/>" +
  "<rect x='7' y='19' width='6' height='6' rx='1.6'/>" +
  "<rect x='19' y='19' width='2.6' height='2.6' rx='.6'/>" +
  "<rect x='23.4' y='19' width='2.6' height='2.6' rx='.6'/>" +
  "<rect x='19' y='23.4' width='2.6' height='2.6' rx='.6'/>" +
  "</g></svg>"
);

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "oklch(0.60 0.12 195)",
  "heroLayout": "showcase",
  "bgTone": "neutral",
  "lum3d": 0.5,
  "con3d": 1.25,
  "sat3d": 1,
  "rel3d": 1.3,
  "ang3d": -30,
  "stageBg": "sombre",
  "packLum": 0.45,
  "packCon": 1.45,
  "ctaX1": 45.87, "ctaY1": 66.42, "ctaZ1": 1,
  "ctaX2": 62.7, "ctaY2": 53.85, "ctaZ2": 1,
  "ctaX3": 39.4, "ctaY3": 57.25, "ctaZ3": 1,
  "ctaX4": 56.53, "ctaY4": 59.41, "ctaZ4": 1,
  "ctaX5": 50.9, "ctaY5": 59.56, "ctaZ5": 1,
  "ctaDrag": false
}/*EDITMODE-END*/;

const ACCENTS = [
  "oklch(0.58 0.15 255)", // blue
  "oklch(0.58 0.15 150)", // green
  "oklch(0.60 0.12 195)", // teal
  "oklch(0.55 0.16 285)", // indigo
  "oklch(0.66 0.15 55)",  // orange
];

function Header({ t, lang, setLang, route, go, cartCount }) {
  return React.createElement(
    "header", { className: "app-header" },
    React.createElement("div", { className: "container app-header__inner" },
      React.createElement("div", { className: "brand", onClick: () => go("home") },
        React.createElement(window.Logo, { size: 30 }),
        React.createElement("span", { className: "brand__name" }, "QLEQLE"),
      ),
      React.createElement("div", { className: "header-spacer" }),
      React.createElement("nav", { className: "header-nav header-nav--desktop" },
        React.createElement("button", { className: "nav-link" + (route === "home" ? " is-active" : ""), onClick: () => go("home") }, t("nav_home")),
        React.createElement("button", { className: "nav-link" + (route === "customize" ? " is-active" : ""), onClick: () => go("customize") }, t("nav_create")),
      ),
      React.createElement("div", { className: "lang-toggle" },
        React.createElement("button", { className: lang === "fr" ? "is-active" : "", onClick: () => setLang("fr") }, "FR"),
        React.createElement("button", { className: lang === "en" ? "is-active" : "", onClick: () => setLang("en") }, "EN"),
      ),
      React.createElement("button", { className: "cart-btn", onClick: () => go("cart"), "aria-label": t("nav_cart") },
        React.createElement("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" },
          React.createElement("path", { d: "M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z" }),
          React.createElement("path", { d: "M3 6h18" }),
          React.createElement("path", { d: "M16 10a4 4 0 0 1-8 0" }),
        ),
        cartCount > 0 ? React.createElement("span", { className: "cart-badge" }, cartCount) : null,
      ),
    )
  );
}

function Footer({ t, lang, go, route }) {
  const [showPrivacy, setShowPrivacy] = React.useState(false);
  return React.createElement(
    "footer", { className: "app-footer" },
    React.createElement("div", { className: "container app-footer__inner" },
      React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 9 } },
        React.createElement(window.Logo, { size: 22 }),
        React.createElement("span", { style: { fontWeight: 600, color: "var(--ink)" } }, "QLEQLE"),
      ),
      React.createElement("span", { className: "faint" }, "·"),
      React.createElement("span", null, "© 2026 · " + t("tagline")),
      React.createElement("div", { className: "header-spacer" }),
      React.createElement("button", { className: "nav-link" + (route === "mentions" ? " is-active" : ""), onClick: () => go("mentions"), style: { fontSize: 13 } }, lang === "en" ? "Legal notice" : "Mentions légales"),
      React.createElement("button", { className: "nav-link" + (route === "cgv" ? " is-active" : ""), onClick: () => go("cgv"), style: { fontSize: 13 } }, "CGV"),
      React.createElement("button", { className: "nav-link", onClick: () => setShowPrivacy(true), style: { fontSize: 13 } }, t("footer_privacy")),
      React.createElement("button", { className: "nav-link" + (route === "admin" ? " is-active" : ""), onClick: () => go("admin"), style: { fontSize: 13 } }, t("nav_admin")),
    ),
    showPrivacy && React.createElement("div", { className: "modal-overlay", onClick: () => setShowPrivacy(false) },
      React.createElement("div", { className: "modal card", style: { maxWidth: 440 }, onClick: (e) => e.stopPropagation() },
        React.createElement("div", { className: "modal-head" },
          React.createElement("div", { style: { fontWeight: 700, fontSize: 17 } }, t("footer_privacy")),
          React.createElement("button", { className: "icon-btn", onClick: () => setShowPrivacy(false) }, "✕")),
        React.createElement("hr", { className: "hr" }),
        React.createElement("p", { className: "muted", style: { fontSize: 14, lineHeight: 1.6, marginTop: 16 } }, t("privacy_body")),
      )
    )
  );
}

// Tweaks persistence: the host's save mechanism targets the previewed HTML
// file, not this .jsx module — so we mirror tweak values in localStorage and
// restore them on load, otherwise slider changes vanish on refresh.
function loadSavedTweaks() {
  try { return { ...TWEAK_DEFAULTS, ...JSON.parse(localStorage.getItem("qbt_tweaks") || "{}") }; }
  catch (e) { return TWEAK_DEFAULTS; }
}

function App() {
  const [tw, setTweakRaw] = window.useTweaks(loadSavedTweaks());
  const [ctaSel, setCtaSel] = React.useState(1);
  const setTweak = React.useCallback((k, v) => {
    setTweakRaw(k, v);
    try {
      const saved = JSON.parse(localStorage.getItem("qbt_tweaks") || "{}");
      const edits = typeof k === "object" && k !== null ? k : { [k]: v };
      localStorage.setItem("qbt_tweaks", JSON.stringify({ ...saved, ...edits }));
    } catch (e) { /* storage unavailable — non-fatal */ }
  }, [setTweakRaw]);
  const [lang, setLang] = React.useState(() => localStorage.getItem("qbt_lang") || "fr");
  React.useEffect(() => { localStorage.setItem("qbt_lang", lang); }, [lang]);
  const t = React.useMemo(() => window.makeT(lang), [lang]);

  const [route, setRoute] = React.useState("home");
  const [selProduct, setSelProduct] = React.useState(null);
  const [editing, setEditing] = React.useState(null);
  const [lastOrder, setLastOrder] = React.useState(null);

  const cart = window.useCart();
  const ordersApi = window.useOrders();

  function go(r) {
    setRoute(r);
    window.scrollTo({ top: 0, behavior: "auto" });
  }

  function chooseProduct(p) {
    setSelProduct(p);
    setEditing(null);
    go("customize");
  }
  function startCreate() {
    setSelProduct(null);
    setEditing(null);
    go("customize");
  }
  function handleAdd(item) {
    if (editing) cart.remove(editing.lineId);
    cart.add(item);
    setEditing(null);
    go("cart");
  }
  function editItem(item) {
    setEditing(item);
    setSelProduct(window.PRODUCTS.find((p) => p.id === item.productId));
    go("customize");
  }
  function handlePaid(d) {
    const order = {
      id: window.genOrderId(),
      date: Date.now(),
      status: "new",
      items: cart.items,
      total: cart.subtotal,
      customer: d,
    };
    ordersApi.place(order);
    setLastOrder(order);
    cart.clear();
    go("confirmation");
  }

  // Handle the return from Stripe Checkout:
  //   ?paiement=succes → create the order from the saved cart, clear it, show confirmation
  //   ?paiement=annule → back to the cart
  const stripeReturnDone = React.useRef(false);
  React.useEffect(() => {
    if (stripeReturnDone.current) return;
    stripeReturnDone.current = true;
    const params = new URLSearchParams(window.location.search);
    const p = params.get("paiement");
    if (!p) return;
    if (p === "succes") {
      let items = [];
      try { items = JSON.parse(localStorage.getItem("qbt_cart_v1") || "[]"); } catch (e) { items = []; }
      if (items.length) {
        // best-effort customer info: email from the first contact keychain
        let email = "";
        for (const it of items) {
          const u = (it.units || []).find((x) => x.contentType === "contact" && x.email);
          if (u) { email = u.email; break; }
        }
        const order = {
          id: window.genOrderId(),
          date: Date.now(),
          status: "new",
          items,
          total: items.reduce((s, i) => s + (i.price || 0) * (i.qty || 1), 0),
          customer: { email },
          paiement: "stripe",
        };
        ordersApi.place(order);
        setLastOrder(order);
        cart.clear();
        setRoute("confirmation");
      }
    } else if (p === "annule") {
      setRoute("cart");
    }
    // clean the URL so a refresh doesn't replay the flow
    params.delete("paiement");
    const qs = params.toString();
    window.history.replaceState({}, "", window.location.pathname + (qs ? "?" + qs : ""));
  }, []);

  // prefill payment from the first contact keychain in the cart
  const prefill = React.useMemo(() => {
    let u = null;
    for (const i of cart.items) {
      u = (i.units || []).find((x) => x.contentType === "contact");
      if (u) break;
    }
    if (!u) return null;
    return {
      name: `${u.firstName || ""} ${u.lastName || ""}`.trim(),
      email: u.email || "",
      address: "", address2: "", zip: "", city: "", country: "France",
      card: "", exp: "", cvc: "", cardName: "",
    };
  }, [route]);

  // apply tweaks -> CSS vars on body
  React.useEffect(() => {
    document.documentElement.style.setProperty("--accent", tw.accent);
    if (tw.bgTone === "warm") {
      document.documentElement.style.setProperty("--bg", "#faf9f6");
      document.documentElement.style.setProperty("--surface-2", "#f4f2ec");
    } else {
      document.documentElement.style.setProperty("--bg", "#ffffff");
      document.documentElement.style.setProperty("--surface-2", "#f5f5f7");
    }
  }, [tw.accent, tw.bgTone]);

  let screen;
  if (route === "home") screen = React.createElement(window.HomeScreen, { t, lang, heroLayout: tw.heroLayout, packLum: tw.packLum, packCon: tw.packCon, ctaFraming: [1, 2, 3, 4, 5].map((n) => ({ x: tw["ctaX" + n], y: tw["ctaY" + n], z: tw["ctaZ" + n] })), onCtaFrame: tw.ctaDrag ? (n, x, y) => setTweak({ ["ctaX" + n]: x, ["ctaY" + n]: y }) : null, onStart: startCreate, onChoose: chooseProduct });
  else if (route === "customize") screen = React.createElement(window.CustomizeStudio, { t, lang, product: selProduct, initial: editing || null, brightness3d: tw.lum3d, contrast3d: tw.con3d, saturation3d: tw.sat3d, relief3d: tw.rel3d, angle3d: tw.ang3d, stageBg: tw.stageBg, onBack: () => go("home"), onAdd: handleAdd });
  else if (route === "cart") screen = React.createElement(window.CartScreen, { t, lang, cart, onCheckout: () => go("payment"), onContinue: () => go("home"), onEdit: editItem });
  else if (route === "payment") screen = React.createElement(window.PaymentScreen, { t, lang, cart, prefill, onPaid: handlePaid, onBack: () => go("cart") });
  else if (route === "confirmation") screen = React.createElement(window.ConfirmationScreen, { t, lang, order: lastOrder, onHome: () => go("home") });
  else if (route === "admin") screen = React.createElement(window.AdminScreen, { t, lang, orders: ordersApi.orders, setStatus: ordersApi.setStatus, clearAll: ordersApi.clearAll, onBack: () => go("home") });
  else if (route === "mentions" || route === "cgv") screen = React.createElement(window.LegalScreen, { t, lang, kind: route, onBack: () => go("home") });

  return React.createElement(
    React.Fragment, null,
    React.createElement(Header, { t, lang, setLang, route, go, cartCount: cart.count }),
    React.createElement("main", { key: route, style: { flex: 1 } }, screen),
    React.createElement(Footer, { t, lang, go, route }),

    React.createElement(window.TweaksPanel, null,
      React.createElement(window.TweakSection, { label: lang === "en" ? "Brand" : "Marque" }),
      React.createElement(window.TweakColor, { label: lang === "en" ? "Accent" : "Accent", value: tw.accent, options: ACCENTS, onChange: (v) => setTweak("accent", v) }),
      React.createElement(window.TweakRadio, { label: lang === "en" ? "Background" : "Fond", value: tw.bgTone, options: ["neutral", "warm"], onChange: (v) => setTweak("bgTone", v) }),
      React.createElement(window.TweakSection, { label: lang === "en" ? "Home page" : "Accueil" }),
      React.createElement(window.TweakRadio, { label: lang === "en" ? "Hero layout" : "Disposition", value: tw.heroLayout, options: ["centered", "split", "showcase"], onChange: (v) => setTweak("heroLayout", v) }),
      React.createElement(window.TweakSection, { label: lang === "en" ? "CTA photos — framing" : "Photos CTA — cadrage" }),
      React.createElement(window.TweakToggle, { label: lang === "en" ? "Drag to reframe" : "Recadrage à la souris", value: !!tw.ctaDrag, onChange: (v) => setTweak("ctaDrag", v) }),
      React.createElement(window.TweakRadio, { label: lang === "en" ? "Photo" : "Photo", value: String(ctaSel), options: ["1", "2", "3", "4"], onChange: (v) => setCtaSel(Number(v)) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Horizontal" : "Horizontal", value: tw["ctaX" + ctaSel], min: 0, max: 100, step: 1, onChange: (v) => setTweak("ctaX" + ctaSel, v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Vertical" : "Vertical", value: tw["ctaY" + ctaSel], min: 0, max: 100, step: 1, onChange: (v) => setTweak("ctaY" + ctaSel, v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Zoom" : "Zoom", value: tw["ctaZ" + ctaSel], min: 1, max: 2.5, step: 0.05, onChange: (v) => setTweak("ctaZ" + ctaSel, v) }),
      React.createElement(window.TweakSection, { label: lang === "en" ? "3D preview" : "Aperçu 3D" }),
      React.createElement(window.TweakRadio, { label: lang === "en" ? "Preview glass" : "Fond verre", value: tw.stageBg, options: ["aucun", "clair", "sombre"], onChange: (v) => setTweak("stageBg", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Packs — brightness" : "Packs — luminosité", value: tw.packLum, min: 0.4, max: 2.2, step: 0.05, onChange: (v) => setTweak("packLum", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Packs — contrast" : "Packs — contraste", value: tw.packCon, min: 0.5, max: 1.8, step: 0.05, onChange: (v) => setTweak("packCon", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Brightness" : "Luminosité", value: tw.lum3d, min: 0.4, max: 2, step: 0.05, onChange: (v) => setTweak("lum3d", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Contrast" : "Contraste", value: tw.con3d, min: 0.5, max: 1.8, step: 0.05, onChange: (v) => setTweak("con3d", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Saturation" : "Saturation", value: tw.sat3d, min: 0.4, max: 1.8, step: 0.05, onChange: (v) => setTweak("sat3d", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Relief (shadows)" : "Relief (ombres)", value: tw.rel3d, min: 0.2, max: 2, step: 0.05, onChange: (v) => setTweak("rel3d", v) }),
      React.createElement(window.TweakSlider, { label: lang === "en" ? "Light angle" : "Angle lumière", value: tw.ang3d, min: -90, max: 90, step: 3, onChange: (v) => setTweak("ang3d", v) }),
      React.createElement(window.TweakButton, { label: lang === "en" ? "Reset lighting" : "Réinitialiser l'éclairage", onClick: () => setTweak({ lum3d: 1, con3d: 1, sat3d: 1, rel3d: 1, ang3d: -27 }) }),
    ),
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App));
