/* global React */
const { useState: useStateUI } = React;

// ============================================================
// Icon — tiny monoline set, nothing fancy
// ============================================================
function Icon({ name, size = 16, stroke = 1.5 }) {
  const c = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
              stroke: "currentColor", strokeWidth: stroke,
              strokeLinecap: "round", strokeLinejoin: "round" };
  switch (name) {
    case "arrow-right": return (<svg {...c}><path d="M5 12h14"/><path d="M13 6l6 6-6 6"/></svg>);
    case "arrow-down":  return (<svg {...c}><path d="M12 5v14"/><path d="M6 13l6 6 6-6"/></svg>);
    case "arrow-up":    return (<svg {...c}><path d="M12 19V5"/><path d="M6 11l6-6 6 6"/></svg>);
    case "menu":        return (<svg {...c}><path d="M3 12h18"/><path d="M3 6h18"/><path d="M3 18h18"/></svg>);
    case "close":       return (<svg {...c}><path d="M6 6l12 12"/><path d="M18 6L6 18"/></svg>);
    case "plus":        return (<svg {...c}><path d="M12 5v14"/><path d="M5 12h14"/></svg>);
    case "minus":       return (<svg {...c}><path d="M5 12h14"/></svg>);
    case "check":       return (<svg {...c}><path d="M4 12l5 5L20 6"/></svg>);
    case "star":        return (<svg {...c} fill="currentColor" stroke="none"><path d="M12 2l2.9 6.9L22 10l-5.5 4.8L18 22l-6-3.8L6 22l1.5-7.2L2 10l7.1-1.1L12 2z"/></svg>);
    case "cart":        return (<svg {...c}><path d="M3 4h2l2.5 12h12l2-8H6.5"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/></svg>);
    case "truck":       return (<svg {...c}><path d="M3 6h11v10H3z"/><path d="M14 9h4l3 3v4h-7"/><circle cx="7" cy="18" r="1.5"/><circle cx="17" cy="18" r="1.5"/></svg>);
    case "shield":      return (<svg {...c}><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6l8-3z"/></svg>);
    case "leaf":        return (<svg {...c}><path d="M20 4c-9 0-14 5-14 12 0 2 1 3 1 3s1-9 10-13"/><path d="M7 19c0-7 5-11 13-11"/></svg>);
    case "beaker":      return (<svg {...c}><path d="M9 3h6"/><path d="M10 3v6L5 19a2 2 0 002 3h10a2 2 0 002-3l-5-10V3"/></svg>);
    case "sun":         return (<svg {...c}><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>);
    case "moon":        return (<svg {...c}><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>);
    case "pencil":      return (<svg {...c}><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>);
    case "camera":      return (<svg {...c}><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>);
    default:            return null;
  }
}

// ============================================================
// Placeholder — striped + mono caption (fallback only)
// ============================================================
function Placeholder({ caption = "PRODUCT SHOT", brand = "KSHOP", aspect = "1 / 1", style, children }) {
  return (
    <div className="ph" style={{ aspectRatio: aspect, ...style }}>
      <div className="ph-stripes" />
      <div className="ph-caption">▢ {caption}</div>
      <div className="ph-brand">{brand}</div>
      {children}
    </div>
  );
}

// ============================================================
// Photo — real image, wrapped with same frame language as Placeholder
// (caption floats bottom-left, small brand mark bottom-right)
// ============================================================
function Photo({ src, caption, brand = "KSHOP", aspect = "1 / 1", style, fit = "cover", bg = "var(--bg-2)", children }) {
  const [loading, setLoading] = useStateUI(!!src);
  React.useEffect(() => { if (src) setLoading(true); }, [src]);
  return (
    <div className="ph" style={{ aspectRatio: aspect, background: bg, ...style }}>
      <img
        src={src}
        alt={caption || ""}
        style={{
          position: "absolute", inset: 0, width: "100%", height: "100%",
          objectFit: fit, display: "block",
          opacity: loading ? 0 : 1, transition: "opacity 220ms ease",
        }}
        loading="lazy"
        onLoad={() => setLoading(false)}
      />
      {loading && (
        <div style={{
          position: "absolute", inset: 0,
          display: "flex", alignItems: "center", justifyContent: "center",
        }}>
          <div style={{
            width: 28, height: 28, borderRadius: "50%",
            border: "2.5px solid var(--line-strong)",
            borderTopColor: "var(--accent)",
            animation: "ks-spin 0.7s linear infinite",
          }} />
        </div>
      )}
      {children}
    </div>
  );
}

// ============================================================
// PhotoEdit — Photo with admin upload overlay
// Uploads to Firebase Storage, saves URL to content/photos in Firestore
// ============================================================
function PhotoEdit({ isAdmin, firestoreField, src: initialSrc, onUploaded, children, ...photoProps }) {
  const [src, setSrc] = useStateUI(initialSrc);
  const [progress, setProgress] = useStateUI(null); // null = idle, 0-100 = uploading

  const handleFile = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    setProgress(0);
    const ext = file.name.split(".").pop().toLowerCase();
    const path = `product-images/${firestoreField}-${Date.now()}.${ext}`;
    const ref = window.kStorage.ref(path);
    const task = ref.put(file);
    task.on(
      "state_changed",
      snap => {
        const pct = snap.totalBytes > 0
          ? Math.round((snap.bytesTransferred / snap.totalBytes) * 100)
          : 0;
        setProgress(pct);
      },
      err => {
        alert("Upload failed: " + err.message);
        setProgress(null);
        e.target.value = "";
      },
      async () => {
        try {
          const url = await ref.getDownloadURL();
          if (window.kDb) {
            await window.kDb.collection("content").doc("photos").set({ [firestoreField]: url }, { merge: true });
          }
          setSrc(url);
          if (onUploaded) onUploaded(url);
        } catch(err) { alert("Save failed: " + err.message); }
        finally { setProgress(null); e.target.value = ""; }
      }
    );
  };

  const uploading = progress !== null;

  return (
    <Photo src={src} {...photoProps}>
      {children}
      {isAdmin && (
        <label
          title={uploading ? `Uploading ${progress}%` : "Replace photo"}
          style={{
            position: "absolute", bottom: 8, left: 8,
            display: "flex", flexDirection: "column", gap: 4,
            padding: "6px 10px", borderRadius: 8,
            background: "color-mix(in oklab, var(--bg) 85%, transparent)",
            backdropFilter: "blur(6px)", border: "1px solid var(--line)",
            cursor: uploading ? "default" : "pointer",
            color: uploading ? "var(--accent)" : "var(--fg-muted)", zIndex: 10,
            minWidth: uploading ? 100 : "auto",
          }}
        >
          <input type="file" accept="image/*" onChange={handleFile} disabled={uploading} style={{ display: "none" }} />
          <div style={{ display: "flex", alignItems: "center", gap: 5 }}>
            <Icon name="camera" size={13} />
            <span className="mono" style={{ fontSize: 10, letterSpacing: "0.08em", whiteSpace: "nowrap" }}>
              {uploading ? `UPLOADING ${progress}%` : "REPLACE"}
            </span>
          </div>
          {uploading && (
            <div style={{ height: 3, borderRadius: 99, background: "var(--line)", overflow: "hidden" }}>
              <div style={{
                height: "100%", borderRadius: 99,
                background: "var(--accent)",
                width: progress + "%",
                transition: "width 200ms ease"
              }} />
            </div>
          )}
        </label>
      )}
    </Photo>
  );
}

// ============================================================
// Logo
// ============================================================
function Brand({ onClick }) {
  return (
    <a className="brand" href="#top" onClick={(e) => { e.preventDefault(); onClick && onClick(); }}>
      <span className="brand-mark" aria-hidden="true" />
      <span>KSHOP24.NET</span>
      <span className="brand-sub">/ Cambodia termite defense</span>
    </a>
  );
}

// ============================================================
// Nav
// ============================================================
function Nav({ route, setRoute, cartCount, cartOpen, openCart, theme, setTheme, isAdmin }) {
  const [mobileOpen, setMobileOpen] = useStateUI(false);
  const drawerRef = React.useRef(null);

  React.useEffect(() => {
    if (!mobileOpen) return;
    const drawer = drawerRef.current;
    if (!drawer) return;
    const focusables = drawer.querySelectorAll('button:not([disabled]), [href], input, [tabindex]:not([tabindex="-1"])');
    const first = focusables[0];
    const last  = focusables[focusables.length - 1];
    first?.focus();
    const onKey = (e) => {
      if (e.key === 'Escape') { setMobileOpen(false); return; }
      if (e.key !== 'Tab') return;
      if (e.shiftKey) {
        if (document.activeElement === first) { e.preventDefault(); last?.focus(); }
      } else {
        if (document.activeElement === last) { e.preventDefault(); first?.focus(); }
      }
    };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [mobileOpen]);
  const links = [
    { id: "home",   label: "ទំព័រដើម",  sub: "Home"         },
    { id: "how",    label: "វិធីប្រើ",   sub: "How it works" },
    { id: "learn",  label: "សំណួរ",     sub: "FAQ"          },
    { id: "account",label: "គណនី",      sub: "Account"      },
  ];

  const handleNav = (id) => { setRoute(id); setMobileOpen(false); };

  return (
    <>
      <header className="nav">
        <div className="wrap nav-inner">
          <div className="nav-left gap-24">
            <Brand onClick={() => setRoute("home")} />
          </div>
          <nav className="nav-links">
            {links.filter(l => l.id !== "account").map(l => (
              <button
                key={l.id}
                type="button"
                className={"nav-link" + (route === l.id ? " is-active" : "")}
                onClick={() => setRoute(l.id)}
                title={l.sub}
                aria-current={route === l.id ? "page" : undefined}
              >
                <span className="km-sans" style={{ fontSize: "var(--text-xs)" }}>{l.label}</span>
                <span className="nav-link-sub">{l.sub}</span>
              </button>
            ))}
          </nav>
          <div className="nav-right gap-8">
            {/* Theme toggle — utility first, leftmost in right cluster */}
            <button
              type="button"
              className="theme-toggle"
              onClick={() => setTheme(theme === "light" ? "dark" : "light")}
              aria-label={theme === "light" ? "Switch to dark mode · ប្ដូរទៅងងឹត" : "Switch to light mode · ប្ដូរទៅភ្លឺ"}
              title={theme === "light" ? "Dark mode" : "Light mode"}
            >
              <Icon name={theme === "light" ? "moon" : "sun"} size={16} />
            </button>
            {isAdmin && (
              <button type="button" className={"nav-link" + (route === "admin" ? " is-active" : "")} onClick={() => setRoute("admin")}>
                <span className="km-sans" style={{ fontSize: "var(--text-xs)" }}>គ្រប់គ្រង</span>
                <span className="nav-link-sub">Admin</span>
              </button>
            )}
            <button type="button" className={"nav-link" + (route === "account" ? " is-active" : "")} onClick={() => setRoute("account")}>
              <span className="km-sans" style={{ fontSize: "var(--text-xs)" }}>គណនី</span>
              <span className="nav-link-sub">Account</span>
            </button>
            <button type="button" className={"cart-btn" + (cartOpen ? " is-active" : "")} onClick={openCart} aria-label="Open cart">
              <span className="dot">{cartCount}</span>
              <span style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 1 }}>
                <span className="km-sans" style={{ fontSize: "var(--text-xs)" }}>កន្ត្រក</span>
                <span className="nav-link-sub">Cart</span>
              </span>
            </button>
            {/* Hamburger — visible only on mobile via CSS */}
            <button
              type="button"
              className="mobile-menu-btn"
              onClick={() => setMobileOpen(true)}
              aria-label="Open menu"
              aria-expanded={mobileOpen ? "true" : "false"}
            >
              <Icon name="menu" size={20} />
            </button>
          </div>
        </div>
      </header>

      {/* Mobile slide-in drawer */}
      <div
        className={"mobile-drawer-scrim" + (mobileOpen ? " open" : "")}
        onClick={() => setMobileOpen(false)}
        aria-hidden="true"
      />
      <nav ref={drawerRef} className={"mobile-drawer" + (mobileOpen ? " open" : "")} aria-label="Mobile navigation">
        <div style={{ padding: "16px 24px 20px", borderBottom: "1px solid var(--line)" }}>
          <Brand onClick={() => { setRoute("home"); setMobileOpen(false); }} />
        </div>
        {links.map(l => (
          <button
            key={l.id}
            type="button"
            className={"mobile-drawer-link" + (route === l.id ? " is-active" : "")}
            onClick={() => handleNav(l.id)}
          >
            <span className="mobile-drawer-link-kh">{l.label}</span>
            <span className="mobile-drawer-link-en">{l.sub}</span>
          </button>
        ))}
        {isAdmin && (
          <button
            type="button"
            className={"mobile-drawer-link" + (route === "admin" ? " is-active" : "")}
            onClick={() => handleNav("admin")}
          >
            <span className="mobile-drawer-link-kh">គ្រប់គ្រង</span>
            <span className="mobile-drawer-link-en">Admin</span>
          </button>
        )}
        <div style={{ padding: "16px 28px", display: "flex", flexDirection: "column", gap: 10, marginTop: "auto" }}>
          <button type="button" className="btn btn-primary" style={{ width: "100%" }} onClick={openCart} aria-label="Open cart">
            <span className="km-sans">កន្ត្រក</span> · Cart
            {cartCount > 0 && <span className="dot" style={{ marginLeft: 6 }}>{cartCount}</span>}
          </button>
        </div>
      </nav>
    </>
  );
}

// ============================================================
// Ticker — bilingual announcement bar (Khmer phrase + English)
// ============================================================
function Ticker({ isAdmin }) {
  const { shippingFreeThreshold = 30 } = window.STORE_CONFIG || {};
  const [tickerItems, setTickerItems] = useStateUI(() => window.TICKER_ITEMS || []);
  const [editing, setEditing] = useStateUI(false);
  const [draft, setDraft] = useStateUI([]);
  const [saving, setSaving] = useStateUI(false);

  const ta = {
    width: "100%", fontFamily: "inherit", fontSize: 13, lineHeight: 1.5,
    padding: "8px 12px", border: "1px solid var(--line-strong)", borderRadius: 6,
    background: "var(--bg)", color: "var(--fg)", resize: "vertical",
  };

  const startEdit = () => { setDraft(tickerItems.map(it => ({ ...it }))); setEditing(true); };
  const cancelEdit = () => setEditing(false);
  const handleSave = async () => {
    setSaving(true);
    try {
      if (window.kDb) await window.kDb.collection("content").doc("ticker").set({ items: draft });
      setTickerItems(draft);
      window.TICKER_ITEMS = draft;
      setEditing(false);
    } catch(e) { alert("Save failed: " + e.message); }
    setSaving(false);
  };

  const freeShipping = {
    kh: "ដឹកជញ្ជូនដោយឥតគិតថ្លៃ២៥ខេត្តក្រុង",
    en: "Free delivery",
  };
  const allItems = [freeShipping, ...tickerItems];
  const rendered = allItems.map((it, i) => (
    <span key={i}>
      <span className="km-sans" style={{ marginRight: 10, color: "var(--fg)", letterSpacing: 0 }}>{it.kh}</span>
      <span style={{ color: "var(--fg-muted)" }}>— {it.en}</span>
    </span>
  ));
  const track = [...rendered, ...rendered];

  return (
    <>
      {isAdmin && editing && (
        <div style={{ border: "2px solid var(--accent)", borderRadius: 10, padding: "20px 24px", margin: "12px 32px", background: "var(--bg)" }}>
          <div className="col gap-12">
            <div className="row justify-between items-center">
              <span className="mono text-muted" style={{ fontSize: "var(--text-2xs)", letterSpacing: "0.12em" }}>EDITING · TICKER</span>
              <button onClick={cancelEdit} style={{ background: "transparent", border: 0, cursor: "pointer", color: "var(--fg-muted)", fontSize: 20, lineHeight: 1 }}>×</button>
            </div>
            <span className="mono text-muted" style={{ fontSize: "var(--text-2xs)" }}>
              Free shipping message is auto-generated. Add extra announcement items below.
            </span>
            {draft.map((item, i) => (
              <div key={i} className="col gap-8" style={{ padding: "12px 0", borderTop: "1px solid var(--line)" }}>
                <div className="row justify-between items-center">
                  <span className="mono text-muted" style={{ fontSize: "var(--text-2xs)", letterSpacing: "0.1em" }}>ITEM {i + 1}</span>
                  <button onClick={() => setDraft(d => d.filter((_, j) => j !== i))}
                    style={{ background: "transparent", border: 0, cursor: "pointer", color: "var(--accent)", fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
                    Delete
                  </button>
                </div>
                <textarea className="km-sans" rows={2} placeholder="ខ្មែរ" value={item.kh || ""}
                  onChange={e => setDraft(d => d.map((it, j) => j === i ? { ...it, kh: e.target.value } : it))} style={ta} />
                <textarea rows={2} placeholder="English" value={item.en || ""}
                  onChange={e => setDraft(d => d.map((it, j) => j === i ? { ...it, en: e.target.value } : it))} style={ta} />
              </div>
            ))}
            <button onClick={() => setDraft(d => [...d, { kh: "", en: "" }])}
              style={{ alignSelf: "flex-start", background: "transparent", border: "1.5px dashed var(--line-strong)", borderRadius: 6, cursor: "pointer", color: "var(--fg-muted)", padding: "8px 16px", fontFamily: "var(--font-mono)", fontSize: "var(--text-2xs)", letterSpacing: "0.08em" }}>
              + ADD ITEM
            </button>
            <div className="row gap-8 items-center">
              <button className="btn btn-primary" onClick={handleSave} disabled={saving} style={{ fontSize: "var(--text-xs)" }}>{saving ? "Saving…" : "Save"}</button>
              <button className="btn" onClick={cancelEdit} style={{ fontSize: "var(--text-xs)" }}>Cancel</button>
            </div>
          </div>
        </div>
      )}
      <div className="ticker" aria-hidden="true" style={{ position: "relative" }}>
        {isAdmin && !editing && (
          <button onClick={startEdit} style={{
            position: "absolute", right: 12, top: "50%", transform: "translateY(-50%)",
            display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 999,
            border: "1.5px solid var(--accent)", background: "var(--bg-2)", cursor: "pointer",
            color: "var(--accent)", fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.1em",
            boxShadow: "0 2px 8px rgba(0,0,0,0.25)", zIndex: 10
          }}>
            <Icon name="pencil" size={11} /> EDIT TICKER
          </button>
        )}
        <div className="ticker-track">
          {track.map((n, i) => <span key={i}>· {n}</span>)}
        </div>
      </div>
    </>
  );
}

// ============================================================
// Stars
// ============================================================
function Stars({ n = 5, size = 13 }) {
  return (
    <span role="img" aria-label={`${n} out of 5 stars`} style={{ display: "inline-flex", gap: 2, color: "var(--accent)" }}>
      {Array.from({ length: n }).map((_, i) => <Icon key={i} name="star" size={size} />)}
    </span>
  );
}

// ============================================================
// Stepper
// ============================================================
function Stepper({ value, onChange, min = 1, max = 99 }) {
  return (
    <div className="stepper" role="group" aria-label="Quantity">
      <button type="button" onClick={() => onChange(Math.max(min, value - 1))} aria-label="Decrease">
        <Icon name="minus" size={14} />
      </button>
      <span className="val">{value}</span>
      <button type="button" onClick={() => onChange(Math.min(max, value + 1))} aria-label="Increase">
        <Icon name="plus" size={14} />
      </button>
    </div>
  );
}

// ============================================================
// BackToTop — appears after scrolling 400px
// ============================================================
function BackToTop() {
  const [visible, setVisible] = useStateUI(false);
  React.useEffect(() => {
    const handler = () => setVisible(window.scrollY > 400);
    window.addEventListener("scroll", handler, { passive: true });
    return () => window.removeEventListener("scroll", handler);
  }, []);
  return (
    <button
      type="button"
      className={"back-to-top" + (visible ? " visible" : "")}
      onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}
      aria-label="ត្រឡប់ទៅលើ · Back to top"
    >
      <Icon name="arrow-up" size={16} />
    </button>
  );
}

// ── Print slip ──────────────────────────────────────────────────────────────
function printSlip(order, qrDataUrl = null, win = null, merchantName = "KSHOP") {
  const date = order.createdAt?.toDate?.().toLocaleDateString("en-US", {
    day: "numeric", month: "long", year: "numeric"
  }) || "—";
  const orderId   = "KS-" + order.id.slice(0, 10).toUpperCase();
  const STATUS_KH_P = { pending:"រង់ចាំ", confirmed:"បញ្ជាក់", shipped:"កំពុងដឹក", delivered:"បានដឹក" };
  const STATUS_EN_P = { pending:"PENDING", confirmed:"CONFIRMED", shipped:"SHIPPED", delivered:"DELIVERED" };
  const PAY_LABEL   = { cod:"Cash on Delivery (COD)", aba:"ABA · KHQR", khqr:"ABA · KHQR" };

  const rows = (order.items || []).map(it => {
    const lineTotal = Number((it.price || 0) * it.qty).toFixed(2);
    return `<tr>
      <td><span class="km">${it.labelKh || ""}</span><span class="en-sub">${it.label || ""}</span></td>
      <td class="center">×${it.qty}</td>
      <td class="right mono">$${Number(it.price || 0).toFixed(2)}</td>
      <td class="right mono">$${lineTotal}</td>
    </tr>`;
  }).join("");

  const shippingCell = Number(order.shipping || 0) === 0
    ? `<span style="color:#888;font-style:italic">Free</span>`
    : `<span class="mono">$${Number(order.shipping || 0).toFixed(2)}</span>`;

  const html = `<!DOCTYPE html>
<html lang="km">
<head>
<meta charset="utf-8">
<title>${orderId} · KSHOP24.NET</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Khmer:wght@400;600&family=Inter+Tight:wght@400;500;600&display=swap" rel="stylesheet">
<style>
@page{size:57mm auto;margin:2mm 0}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter Tight',sans-serif;color:#111;width:57mm;padding:0 3mm;font-size:10px;line-height:1.5}
.km{font-family:'Noto Sans Khmer',sans-serif}
.mono{font-family:'Courier New',monospace;letter-spacing:0}
.center{text-align:center}
.right{text-align:right}
.bold{font-weight:600}

/* Header */
.brand{font-size:16px;font-weight:700;text-align:center;margin-bottom:1mm}
.brand-sub{font-size:8px;letter-spacing:0.1em;text-transform:uppercase;color:#777;text-align:center;margin-bottom:2mm}
.divider{border:none;border-top:1px dashed #aaa;margin:2mm 0}
.divider-solid{border:none;border-top:1px solid #111;margin:2mm 0}
.order-id{font-family:'Courier New',monospace;font-size:11px;font-weight:600;letter-spacing:0.05em;text-align:center}
.order-date{font-size:8px;color:#888;text-align:center;margin-bottom:1mm}
.status{font-size:8px;letter-spacing:0.06em;text-align:center;border:1px solid #111;border-radius:99px;padding:1px 7px;display:inline-block}
.status-wrap{text-align:center;margin-bottom:2mm}

/* Customer */
.row{display:flex;justify-content:space-between;gap:2mm;padding:1mm 0;border-bottom:1px dotted #e0e0e0}
.row:last-child{border-bottom:none}
.lbl{color:#888;font-size:9px;flex-shrink:0;width:16mm}
.val{font-size:10px;font-weight:500;text-align:right;word-break:break-word}

/* Items */
.item{padding:1.5mm 0;border-bottom:1px dotted #e8e8e8}
.item-name{font-size:10px;font-weight:500}
.item-name .km{font-size:10px}
.item-sub{font-size:8px;color:#888;margin-top:0.5mm}
.item-line{display:flex;justify-content:space-between;margin-top:1mm;font-size:9px;color:#555}

/* Totals */
.tot-row{display:flex;justify-content:space-between;padding:0.8mm 0;font-size:10px;color:#555}
.tot-row.grand{border-top:1px solid #111;margin-top:1.5mm;padding-top:1.5mm;font-weight:700;color:#111;font-size:12px}

/* Notes */
.notes{font-size:9px;color:#555;font-style:italic;padding:1.5mm;border:1px solid #ddd;border-radius:3px;margin-bottom:2mm}

/* QR */
.qr-wrap{text-align:center;margin:2mm 0}
.qr-label{font-size:8px;color:#888;letter-spacing:0.08em;text-transform:uppercase;margin-bottom:1mm}
.qr-amount{font-size:14px;font-weight:700;margin-bottom:1.5mm}

/* Footer */
.footer{margin-top:3mm;text-align:center}
.footer .km{font-size:11px;display:block;margin-bottom:1mm}
.footer .en{font-size:8px;color:#999;line-height:1.6}

/* Print button */
.print-btn{position:fixed;top:10px;right:10px;background:#111;color:#fff;border:none;cursor:pointer;padding:6px 14px;border-radius:5px;font-size:12px;font-family:inherit;font-weight:500}
@media print{.print-btn{display:none!important}}
</style>
</head>
<body>
<button class="print-btn" onclick="window.print()">Print</button>

<div class="brand">KSHOP24.NET</div>
<div class="brand-sub">Cambodia Termite Defense</div>
<hr class="divider-solid">

<div class="order-id">${orderId}</div>
<div class="order-date">${date}</div>
<div class="status-wrap">
  <span class="status"><span class="km">${STATUS_KH_P[order.status] || order.status}</span> · ${STATUS_EN_P[order.status] || (order.status || "").toUpperCase()}</span>
</div>
<hr class="divider">

<div class="row"><span class="lbl km">ឈ្មោះ</span><span class="val">${order.name || "—"}</span></div>
<div class="row"><span class="lbl km">ទូរស័ព្ទ</span><span class="val mono">${order.phone || "—"}</span></div>
<div class="row"><span class="lbl km">អាសយដ្ឋាន</span><span class="val">${order.address || "—"}</span></div>
<div class="row"><span class="lbl km">ទូទាត់</span><span class="val">${PAY_LABEL[order.paymentMethod] || (order.paymentMethod || "COD").toUpperCase()}</span></div>

${order.notes ? `<hr class="divider"><div class="notes">"${order.notes}"</div>` : ""}

<hr class="divider">
${(order.items || []).map(it => `
<div class="item">
  <div class="item-name"><span class="km">${it.labelKh || ""}</span></div>
  <div class="item-sub">${it.label || ""}</div>
  <div class="item-line">
    <span>×${it.qty} × $${Number(it.price || 0).toFixed(2)}</span>
    <span class="mono bold">$${Number((it.price || 0) * it.qty).toFixed(2)}</span>
  </div>
</div>`).join("")}

<hr class="divider">
<div class="tot-row"><span>Subtotal</span><span class="mono">$${Number(order.subtotal || 0).toFixed(2)}</span></div>
<div class="tot-row"><span>Shipping</span><span class="mono">${Number(order.shipping || 0) === 0 ? "Free" : "$" + Number(order.shipping || 0).toFixed(2)}</span></div>
<div class="tot-row grand"><span><span class="km">សរុប</span> Total</span><span class="mono">$${Number(order.total || 0).toFixed(2)}</span></div>

${qrDataUrl ? `
<hr class="divider">
<div class="qr-wrap">
  <div style="display:inline-block;border-radius:10px;overflow:hidden;box-shadow:0 2px 12px rgba(0,0,0,0.15)">
    <!-- Red header with angled tab -->
    <div style="background:#E21A1A;height:40px;display:flex;align-items:flex-start;justify-content:center;padding-top:2px;clip-path:polygon(0 0,100% 0,100% 100%,91.8% 67.9%,0 67.9%)">
      <svg width="84" height="24" viewBox="12 14 42 13" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M39.0751 19.3384V22.1689H36.1988C35.9038 22.1689 35.6826 21.933 35.6826 21.6609V19.3565C35.6826 19.0662 35.9223 18.8485 36.1988 18.8485H38.5404C38.8539 18.8303 39.0751 19.048 39.0751 19.3384Z" fill="white"/>
        <path d="M52.5535 20.4817H51.1153C51.1153 18.7942 49.7141 17.4153 47.9994 17.4153C46.635 17.4153 45.4366 18.2862 45.0309 19.5563C44.9387 19.8648 44.8834 20.1732 44.8834 20.4817V24.9815H44.8466C44.0722 24.9815 43.4453 24.3646 43.4453 23.6025V20.4817H43.4637C43.4637 19.2478 43.98 18.0685 44.9019 17.2157C45.75 16.4355 46.8563 16 48.0178 16C50.5253 16 52.5535 18.014 52.5535 20.4817Z" fill="white"/>
        <path d="M52.5715 24.9814L50.5433 24.9996L50.0455 24.5097L48.9393 23.421L47.4089 21.915H49.4371L52.5715 24.9814Z" fill="white"/>
        <path d="M39.5549 23.5662H35.2221C34.6874 23.5662 34.2633 23.1489 34.2633 22.6227V18.3588C34.2633 17.8326 34.6874 17.4153 35.2221 17.4153H39.5549C40.0896 17.4153 40.5137 17.8326 40.5137 18.3588V22.6227L41.9518 24.038V17.379C41.9518 16.6169 41.3249 16 40.5505 16H34.2264C33.4521 16 32.8252 16.6169 32.8252 17.379V23.6025C32.8252 24.3646 33.4521 24.9815 34.2264 24.9815H40.993L39.5549 23.5662Z" fill="white"/>
        <path d="M21.9466 24.9996H19.9185L15.6778 20.8083V24.9996H14V16H15.6778V20.0099L19.7525 16H21.7438L17.3188 20.3184L21.9466 24.9996Z" fill="white"/>
        <path d="M29.5243 16H31.1652V24.9996H29.5243V21.0986H24.8411V24.9996H23.2002V16H24.8411V19.7559H29.5243V16Z" fill="white"/>
      </svg>
    </div>
    <!-- White body -->
    <div style="background:#fff;padding:6px 10px 10px;text-align:center">
      <div style="font-size:9px;font-weight:600;color:#222;letter-spacing:0.08em;text-transform:uppercase;margin-bottom:3px">${merchantName}</div>
      <div style="display:flex;align-items:baseline;justify-content:center;gap:3px;margin-bottom:5px">
        <span style="font-size:22px;font-weight:700;color:#0d0d0d;letter-spacing:-0.02em;line-height:1;font-family:'Inter Tight',sans-serif;font-variant-numeric:tabular-nums">${Number(order.total||0).toFixed(2)}</span>
        <span style="font-size:8px;font-weight:500;color:#999;padding-bottom:2px">USD</span>
      </div>
      <div style="border-top:1px dashed rgba(0,0,0,0.18);margin:0 0 7px"></div>
      <div style="position:relative;width:130px;height:130px;margin:0 auto">
        <img src="${qrDataUrl}" width="130" height="130" alt="KHQR" style="display:block;image-rendering:pixelated" />
        <div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:26px;height:26px;border-radius:50%;background:#111;border:2px solid #fff;display:flex;align-items:center;justify-content:center">
          <span style="font-size:13px;font-weight:700;color:#fff;line-height:1;font-family:sans-serif">$</span>
        </div>
      </div>
      <div style="font-size:8px;color:#aaa;margin-top:4px">ABA · Wing · ACLEDA · Bakong</div>
    </div>
  </div>
</div>` : ""}

<hr class="divider">
<div class="footer">
  <span class="km">អរគុណសម្រាប់ការបញ្ជាទិញ!</span>
  <span class="en">Thank you for your order<br>@KshopKH · kshop24.net</span>
</div>

<script>window.onload=function(){window.print();};</script>
</body></html>`;

  const w = win || window.open("", "_blank", "width=260,height=700,menubar=yes");
  if (w) { w.document.write(html); w.document.close(); }
}

// ── printSlipWithQR — fetches Bakong QR for COD orders before printing ───────
async function printSlipWithQR(order) {
  if (order.paymentMethod !== "cod") { printSlip(order); return; }
  // Open window synchronously from the click event to avoid popup blockers
  const win = window.open("", "_blank", "width=720,height=960,menubar=yes");
  let qrDataUrl = null;
  let merchantName = "KSHOP";
  try {
    const token = await window.kAuth.currentUser.getIdToken();
    const resp = await fetch("https://createkhqr-qsn4ilcqva-uc.a.run.app", {
      method: "POST",
      headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` },
      body: JSON.stringify({ orderId: order.id, forSlip: true }),
    });
    if (!resp.ok) {
      const err = await resp.json().catch(() => ({}));
      console.error("[printSlipWithQR] CF error", resp.status, err);
    } else {
      const data = await resp.json();
      if (data.merchantName) merchantName = data.merchantName;
      if (data.qr && window.qrcode) {
        const gen = window.qrcode(0, "M");
        gen.addData(data.qr);
        gen.make();
        qrDataUrl = gen.createDataURL(4, 8);
      } else {
        console.error("[printSlipWithQR] No qr in response", data);
      }
    }
  } catch (err) {
    console.error("[printSlipWithQR] Error:", err);
  }
  printSlip(order, qrDataUrl, win, merchantName);
}

function RichEditor({ value, onChange, isKh }) {
  const containerRef = React.useRef(null);
  const onChangeRef = React.useRef(onChange);
  onChangeRef.current = onChange;
  React.useEffect(() => {
    const el = containerRef.current;
    if (!el || !window.Quill) return;
    const q = new window.Quill(el, {
      theme: "snow",
      modules: { toolbar: [["bold", "italic"], [{ list: "ordered" }, { list: "bullet" }], ["clean"]] },
    });
    if (isKh) q.root.classList.add("km-sans");
    if (value) q.clipboard.dangerouslyPasteHTML(value);
    q.on("text-change", () => {
      const html = q.root.innerHTML;
      onChangeRef.current(html === "<p><br></p>" ? "" : html);
    });
    return () => { el.innerHTML = ""; };
  }, []);
  return <div ref={containerRef} />;
}

const renderRich = (content) => {
  if (!content) return { __html: "" };
  if (!content.includes("<")) return { __html: content.replace(/\n/g, "<br>") };
  return { __html: content };
};

Object.assign(window, { Icon, Placeholder, Photo, PhotoEdit, Brand, Nav, Ticker, Stars, Stepper, BackToTop, printSlip, printSlipWithQR, RichEditor, renderRich });
