/* global React, I, UI */
// ═══ 🛒 ออเดอร์ออนไลน์ — รับงานจากหน้าเว็บ /order เข้าระบบผลิต ═══
// วงจร: ลูกค้าหย่อนออเดอร์ลงตาราง public_orders (insert-only) →
//   หน้านี้ดูดเข้าคีย์ sync 'sss-online-orders' (เก็บ meta — ไฟล์ DXF/สลิปคงอยู่ในแถวเดิม ไม่บวม LocalStore) →
//   กดรับ = สร้างโปรเจกต์+ใบสั่งงาน+การ์ดตัด(+พับ) อัตโนมัติ →
//   ทุกครั้งที่เปลี่ยนสถานะ (หรือการ์ดตัดเสร็จ) ระบบ mirror สถานะที่ปลอดภัยขึ้น public_store
//   ให้ลูกค้าเห็นที่ลิงก์ติดตามทันที
const { useState: useStateOO, useEffect: useEffectOO } = React;

const OO_KEY = "sss-online-orders";
const OO_STATUSES = ["ได้รับออเดอร์แล้ว", "กำลังตรวจแบบ", "รอชำระมัดจำ", "กำลังผลิต", "ผลิตเสร็จ · รอส่งมอบ", "จัดส่ง/ส่งมอบแล้ว"];
const OO_SPECIAL = ["ต้องแก้ไข/ติดต่อกลับ", "ยกเลิก"];

const ooList = () => (window.lsRead ? window.lsRead(OO_KEY, []) : []) || [];
function ooSave(list) { if (window.lsSyncSet) window.lsSyncSet(OO_KEY, list); }
function ooPatch(orderId, patch) {
  ooSave(ooList().map(o => o.orderId === orderId ? { ...o, ...patch } : o));
  try { window.dispatchEvent(new Event("sss-oo-changed")); } catch (e) {}
}
// SSSDB.client เป็น "ฟังก์ชันสร้าง client" (lazy) — ต้องเรียกก่อนใช้ .from()
const ooClient = () => {
  try {
    const c = window.SSSDB && window.SSSDB.client;
    return typeof c === "function" ? c() : (c || null);
  } catch (e) { return null; }
};

// ── สถานะที่ลูกค้าเห็น (mirror — ไม่มีเบอร์/ชื่อเต็ม/ไฟล์) ──
async function ooMirror(o, extra) {
  const c = ooClient(); if (!c || !o.token) return;
  const cfg = ooPublishedCfg();
  const data = {
    id: o.orderId, status: o.status, note: o.customerNote || "",
    total: (o.price || {}).total || o.finalTotal || null,
    deposit: (o.price || {}).deposit || o.finalDeposit || null,
    specText: o.specText || "",
    cfg: { promptpayId: cfg.promptpayId || "", promptpayName: cfg.promptpayName || "", bankText: cfg.bankText || "" },
    updated: new Date().toISOString(),
    ...(extra || {}),
  };
  try {
    await c.from("public_store").upsert([{ key: `order:${o.orderId}:${o.token}`, data, updated_at: new Date().toISOString() }], { onConflict: "key" });
  } catch (e) {}
}

let _ooCfgCache = null;
function ooPublishedCfg() { return _ooCfgCache || (window.lsRead ? window.lsRead("sss-order-config-local", {}) : {}) || {}; }

// ── ดูดออเดอร์ใหม่จากกล่องรับ (public_orders) ──
async function ooIngest() {
  const c = ooClient(); if (!c) return { added: 0, slips: 0 };
  const { data: rows, error } = await c.from("public_orders").select("id,order_id,kind,data,created_at").order("id", { ascending: true });
  if (error || !Array.isArray(rows)) return { added: 0, slips: 0, error: error && error.message };
  const list = ooList().slice();
  let added = 0, slips = 0;
  rows.forEach(r => {
    if (r.kind === "order") {
      if (list.some(o => o.orderId === r.order_id)) return;
      const d = r.data || {};
      // v2 = หลายชิ้นงาน (items[]) · v1 = ชิ้นเดียว (spec)
      const items = Array.isArray(d.items) && d.items.length ? d.items
        : d.spec ? [{ ...d.spec, kind: d.mode === "dxf" ? "dxf" : "custom", name: (d.spec || {}).dxfName || "ชิ้นงาน" }] : [];
      const specText = items.map(it => `${it.name || "ชิ้นงาน"}${it.kind === "custom" ? "(เขียนแบบ)" : ""} ${it.matName || ""} ${it.T || ""}มม.×${it.qty || 1}${(it.bends || []).length ? "+พับ" : ""}`).join(" · ").slice(0, 160);
      const rec = {
        orderId: r.order_id, rowId: r.id, token: d.token || "", at: d.at || r.created_at,
        mode: d.mode || "v2", items, contact: d.contact || {}, price: d.price || null,
        hasSlip: !!d.slip, specText,
        status: "ได้รับออเดอร์แล้ว", slipRows: [], newSlip: false, projectCode: "", woNo: "", cardId: "",
      };
      list.unshift(rec); added++;
      ooMirror(rec);
    } else if (r.kind === "slip") {
      const o = list.find(x => x.orderId === r.order_id);
      if (o && !(o.slipRows || []).includes(r.id)) { o.slipRows = [...(o.slipRows || []), r.id]; o.newSlip = true; slips++; }
    }
  });
  if (added || slips) { ooSave(list); try { window.dispatchEvent(new Event("sss-oo-changed")); } catch (e) {} }
  return { added, slips };
}

// ── mirror อัตโนมัติ: การ์ดตัดของออเดอร์เสร็จ → สถานะลูกค้าขยับเอง ──
let _ooAutoT = null;
function ooAutoSync() {
  clearTimeout(_ooAutoT);
  _ooAutoT = setTimeout(() => {
    const PX = window.ProjX; if (!PX) return;
    let changed = false;
    const list = ooList().map(o => {
      if (o.status !== "กำลังผลิต" || !o.projectCode || !o.woNo) return o;
      const wo = (PX.pxGet(o.projectCode).workOrders || []).find(w => w.no === o.woNo);
      if (!wo) return o;
      const cards = (wo.cards || []).filter(cd => cd.type !== "deliver");
      if (cards.length && cards.every(cd => cd.status === "เสร็จแล้ว")) {
        changed = true;
        const next = { ...o, status: "ผลิตเสร็จ · รอส่งมอบ" };
        ooMirror(next);
        return next;
      }
      return o;
    });
    if (changed) { ooSave(list); try { window.dispatchEvent(new Event("sss-oo-changed")); } catch (e) {} }
  }, 2500);
}
["sss-projects-changed", "sss-data-synced", "sss-db-loaded"].forEach(ev => window.addEventListener(ev, ooAutoSync));

// ── เฝ้าออเดอร์ใหม่ระดับแอป (ไม่ต้องเปิดหน้านี้ค้าง) — toast + ป้ายบนแดชบอร์ด ──
let _ooPollOn = false;
function ooStartPoll() {
  if (_ooPollOn) return; _ooPollOn = true;
  const tick = async () => {
    const r = await ooIngest();
    if ((r.added || 0) + (r.slips || 0) > 0) {
      try { window.toast && window.toast(`🛒 ${r.added ? `ออเดอร์ออนไลน์ใหม่ ${r.added} รายการ` : ""}${r.added && r.slips ? " · " : ""}${r.slips ? `สลิปใหม่ ${r.slips}` : ""} — ดูที่เมนูออเดอร์ออนไลน์`); } catch (e) {}
    }
  };
  setTimeout(tick, 7000);
  setInterval(tick, 90000);
}
window.addEventListener("sss-db-loaded", ooStartPoll);

// ป้ายแจ้งบนแดชบอร์ด (dashboard.jsx เรียกใช้) — โชว์เมื่อมีออเดอร์รอรับ/สลิปใหม่
function OOBanner({ navigate }) {
  const [, f] = useStateOO(0);
  useEffectOO(() => {
    const h = () => f(n => n + 1);
    window.addEventListener("sss-oo-changed", h);
    return () => window.removeEventListener("sss-oo-changed", h);
  }, []);
  const list = ooList();
  const fresh = list.filter(o => o.status === "ได้รับออเดอร์แล้ว").length;
  const slips = list.filter(o => o.newSlip).length;
  if (!fresh && !slips) return null;
  return (
    <div onClick={() => (navigate ? navigate("online-orders") : (window.location.hash = "#/online-orders"))}
      style={{display: "flex", alignItems: "center", gap: 12, cursor: "pointer", margin: "0 0 14px",
        border: "1.5px solid rgba(15,118,110,0.45)", borderLeft: "6px solid #0f766e", borderRadius: 12,
        background: "linear-gradient(120deg, rgba(15,118,110,0.12), rgba(15,118,110,0.03))", padding: "11px 16px"}}>
      <span style={{fontSize: 22}}>🛒</span>
      <div style={{flex: 1}}>
        <b style={{fontSize: 14.5}}>{fresh ? `ออเดอร์ออนไลน์ใหม่ ${fresh} รายการรอรับ` : ""}{fresh && slips ? " · " : ""}{slips ? `สลิปโอนใหม่ ${slips} ออเดอร์` : ""}</b>
        <div style={{fontSize: 12, color: "var(--ink-3)"}}>ลูกค้าสั่งจากเว็บ — กดเพื่อเปิดเมนูออเดอร์ออนไลน์</div>
      </div>
      <span style={{fontWeight: 800, color: "#0f766e"}}>เปิดดู →</span>
    </div>
  );
}
window.OOBanner = OOBanner;

// ── โหลด OrderEngine (ตัวเดียวกับหน้าเว็บ) สำหรับพรีวิว 2D ──
function ooLoadEngine(cb) {
  if (window.OrderEngine) return cb();
  const sc = document.createElement("script");
  sc.src = "/order/engine.js";
  sc.onload = cb; sc.onerror = cb;
  document.head.appendChild(sc);
}

function OOStatusChip({ s }) {
  const col = s === "ได้รับออเดอร์แล้ว" ? "#b45309" : s === "กำลังตรวจแบบ" ? "#0e7490" : s === "รอชำระมัดจำ" ? "#7c3aed"
    : s === "กำลังผลิต" ? "#1d4ed8" : s === "ผลิตเสร็จ · รอส่งมอบ" ? "#0d9488" : s === "จัดส่ง/ส่งมอบแล้ว" ? "#15803d"
    : "#dc2626";
  return <span style={{fontSize: 11.5, fontWeight: 800, padding: "3px 11px", borderRadius: 999, background: col + "1a", color: col}}>{s}</span>;
}

// ── พรีวิวไฟล์ในออเดอร์: แบบ 2D ทุกชิ้น + รูป + สลิปที่แนบมาตอนสั่ง ──
function OOOrderFiles({ rowId }) {
  const [files, setFiles] = useStateOO(null);
  const [, f] = useStateOO(0);
  useEffectOO(() => {
    let dead = false;
    (async () => {
      const c = ooClient(); if (!c) return;
      const { data } = await c.from("public_orders").select("data").eq("id", rowId);
      const d = ((data || [])[0] || {}).data || {};
      const dxfTexts = Array.isArray(d.dxfTexts) ? d.dxfTexts : (d.dxfText ? [d.dxfText] : []);
      const photos = (d.items || []).flatMap(it => it.photos || []).concat(d.photos || []);
      if (!dead) setFiles({ dxfTexts, slip: d.slip || "", photos });
    })();
    ooLoadEngine(() => { if (!dead) f(n => n + 1); });
    return () => { dead = true; };
  }, [rowId]);
  if (!files) return <div style={{padding: 14, color: "var(--ink-3)", fontSize: 12.5}}>กำลังโหลดไฟล์…</div>;
  const dl = (txt, i) => {
    const a = document.createElement("a");
    a.href = URL.createObjectURL(new Blob([txt], { type: "application/dxf" }));
    a.download = `order-${rowId}-item${i + 1}.dxf`;
    a.click();
  };
  return (
    <div style={{display: "flex", flexDirection: "column", gap: 8}}>
      {files.dxfTexts.map((txt, i) => {
        if (!txt) return null;
        let svg = "";
        if (window.OrderEngine) {
          const d2 = window.OrderEngine.parseDXF(txt);
          if (d2) {
            const b = d2.bbox, pad = Math.max(8, (b.maxX - b.minX) * 0.05);
            svg = `<svg viewBox="${b.minX - pad} ${-(b.maxY + pad)} ${(b.maxX - b.minX) + pad * 2} ${(b.maxY - b.minY) + pad * 2}" style="width:100%;max-height:240px;background:#fff;border-radius:9px">${d2.polylines.map(pl => `<path d="${pl.map((p, k) => (k ? "L" : "M") + p.x.toFixed(1) + " " + (-p.y).toFixed(1)).join(" ")}" fill="none" stroke="#0c0a09" stroke-width="${(b.maxX - b.minX) / 420 || 0.5}"/>`).join("")}</svg>`;
          }
        }
        return (
          <div key={i} style={{border: "1px solid var(--line)", borderRadius: 10, padding: 8}}>
            <div style={{fontSize: 12, fontWeight: 800, marginBottom: 4}}>📐 แบบชิ้นที่ {i + 1}</div>
            {svg ? <div dangerouslySetInnerHTML={{ __html: svg }}/> : <div style={{fontSize: 12, color: "var(--ink-3)"}}>—</div>}
            <window.UI.Btn size="sm" onClick={() => dl(txt, i)} style={{marginTop: 4}}>⬇️ ดาวน์โหลด DXF</window.UI.Btn>
          </div>
        );
      })}
      {(files.photos || []).length > 0 && (
        <div style={{display: "flex", gap: 8, flexWrap: "wrap"}}>
          {files.photos.map((u, i) => <img key={i} src={u} style={{width: 100, height: 76, objectFit: "cover", borderRadius: 8, border: "1px solid var(--line)", cursor: "zoom-in"}}
            onClick={() => window.openPhotoZoom && window.openPhotoZoom(files.photos, i)}/>)}
        </div>
      )}
      {files.slip && (
        <div>
          <div style={{fontSize: 12.5, fontWeight: 800, marginBottom: 4}}>🧾 สลิปแนบมาตอนสั่ง</div>
          <img src={files.slip} style={{width: 130, borderRadius: 9, border: "1px solid var(--line)", cursor: "zoom-in"}}
            onClick={() => window.openPhotoZoom && window.openPhotoZoom([files.slip], 0)}/>
        </div>
      )}
    </div>
  );
}

function OOSlips({ rowIds }) {
  const [imgs, setImgs] = useStateOO([]);
  useEffectOO(() => {
    let dead = false;
    (async () => {
      const c = ooClient(); if (!c || !(rowIds || []).length) return;
      const { data } = await c.from("public_orders").select("id,data").in("id", rowIds);
      if (!dead) setImgs((data || []).map(r => ({ id: r.id, img: (r.data || {}).image, at: (r.data || {}).at })));
    })();
    return () => { dead = true; };
  }, [(rowIds || []).join(",")]);
  if (!(rowIds || []).length) return null;
  return (
    <div style={{marginTop: 8}}>
      <div style={{fontSize: 12.5, fontWeight: 800, marginBottom: 5}}>🧾 สลิปที่ลูกค้าแนบ ({rowIds.length})</div>
      <div style={{display: "flex", gap: 8, flexWrap: "wrap"}}>
        {imgs.map(s => s.img && (
          <img key={s.id} src={s.img} title={s.at} style={{width: 110, height: 140, objectFit: "cover", borderRadius: 9, border: "1px solid var(--line)", cursor: "zoom-in"}}
            onClick={() => window.openPhotoZoom && window.openPhotoZoom(imgs.map(x => x.img).filter(Boolean), imgs.filter(x => x.img).findIndex(x => x.id === s.id))}/>
        ))}
      </div>
    </div>
  );
}

// ── รับออเดอร์ → สร้างโปรเจกต์ + ใบสั่งงาน + การ์ด ──
function ooAccept(o) {
  const PX = window.ProjX, D = window.SSSData;
  // เลขงาน/เลขใบ ใช้ตรรกะเดียวกับหน้าโปรเจกต์ (max+1 กันชนกับของเดิม)
  const users = PX.upLoad() || [];
  const jn = Math.max(0, ...[...users, ...(D.Projects || [])].map(p => Number((String(p.code).match(/JOB-2569-(\d+)/) || [])[1]) || 0)) + 1;
  const code = "JOB-2569-" + String(jn).padStart(3, "0");
  const allEx = {};
  [...users, ...(D.Projects || [])].forEach(p => { allEx[p.code] = PX.pxGet(p.code); });
  const usedWo = new Set(); let maxWo = 0;
  Object.values(allEx).forEach(x => (x.workOrders || []).forEach(w => {
    if (!w || !w.no) return; usedWo.add(w.no);
    const m = /^WO-(\d+)-(\d+)$/.exec(w.no);
    if (m) maxWo = Math.max(maxWo, parseInt(m[2], 10));
  }));
  let wn = maxWo + 1, woNo;
  do { woNo = "WO-2569-" + String(wn).padStart(3, "0"); wn++; } while (usedWo.has(woNo));

  const ct = o.contact || {};
  const its = (o.items && o.items.length) ? o.items : [{ name: "งานออนไลน์ " + o.orderId, qty: 1 }];
  const woItems = its.map(it => ({ name: it.name || "ชิ้นงาน", qty: it.qty || 1, unit: "ชิ้น" }));
  const cardItems = its.map(it => ({ name: it.name || "ชิ้นงาน", qty: it.qty || 1, unit: "ชิ้น",
    material: (it.matName || "") + (it.T ? " " + it.T + "มม." : ""), spec: "", photos: [] }));
  const cards = [window.WOCards.normalize({ type: "cut", title: "งานตัด (ออนไลน์)", status: "รอทำ",
    detail: `ออเดอร์ออนไลน์ ${o.orderId} · ไฟล์ DXF อยู่ในเมนูออเดอร์ออนไลน์`, items: cardItems })];
  const bendIts = its.filter(it => (it.bends || []).length);
  if (bendIts.length) {
    cards.push(window.WOCards.normalize({ type: "bend", title: "งานพับ (ออนไลน์)", status: "รอทำ",
      detail: `ออเดอร์ออนไลน์ ${o.orderId}`,
      items: bendIts.map(it => ({ name: it.name || "ชิ้นงาน", qty: it.qty || 1, unit: "ชิ้น",
        material: (it.matName || "") + (it.T ? " " + it.T + "มม." : ""),
        spec: (it.bends || []).map((b, i) => `เส้น${i + 1}: ${b.angle}°${b.dir < 0 ? "↓" : "↑"}`).join(" · "), photos: [] })) }));
  }
  const itemName = its[0].name || ("งานออนไลน์ " + o.orderId);
  const wo = {
    no: woNo, issueDate: PX.pxToday(), startDate: PX.pxTodayISO(), due: "", priority: "ปกติ",
    detail: `🛒 ออเดอร์ออนไลน์ ${o.orderId} · ${o.specText}\nลูกค้า: ${ct.name || ""} ${ct.phone || ""}${ct.line ? " · LINE " + ct.line : ""}${ct.ship === "ship" ? "\nจัดส่ง: " + (ct.addr || "") : "\nมารับเองที่โรงงาน"}`,
    items: woItems,
    photos: [], assignees: [], assigneeIds: [],
    issuedBy: (window.Session && window.Session.get() && window.Session.get().name) || "ระบบออนไลน์",
    status: "เปิดงาน", cards,
  };
  const proj = {
    code, name: `🛒 ${itemName}`, customer: ct.name || "ลูกค้าออนไลน์", lead: "",
    status: "กำลังผลิต", progress: 0,
    start: PX.pxTodayISO(), end: "", budget: (o.price || {}).total || 0,
    detail: `ออเดอร์ออนไลน์ ${o.orderId} · โทร ${ct.phone || "-"}`,
  };
  PX.upSave([proj, ...users]);
  PX.pxSet(code, { workOrders: [wo], status: "กำลังผลิต" });
  try { window.SSSSync && window.SSSSync.queue && window.SSSSync.queue(); } catch (e) {}
  try { window.dispatchEvent(new Event("sss-projects-changed")); } catch (e) {}
  return { code, woNo, cardId: cards[0].id };
}

function OnlineOrdersPage({ navigate }) {
  const { Btn, Card, PageHead, Drawer } = window.UI;
  const [, force] = useStateOO(0);
  const refresh = () => force(n => n + 1);
  const [tab, setTab] = useStateOO("active");
  const [sel, setSel] = useStateOO(null);
  const [showCfg, setShowCfg] = useStateOO(false);
  const [busy, setBusy] = useStateOO(false);
  const [lastPull, setLastPull] = useStateOO(null);

  const pull = async () => {
    setBusy(true);
    const r = await ooIngest();
    setBusy(false);
    setLastPull(new Date());
    if (r.added || r.slips) window.toast && window.toast(`🛒 ออเดอร์ใหม่ ${r.added} · สลิปใหม่ ${r.slips}`);
    refresh();
  };
  useEffectOO(() => {
    pull();
    const t = setInterval(pull, 60000);
    const h = () => refresh();
    window.addEventListener("sss-oo-changed", h);
    return () => { clearInterval(t); window.removeEventListener("sss-oo-changed", h); };
  }, []);

  const all = ooList();
  const isDone = o => o.status === "จัดส่ง/ส่งมอบแล้ว" || o.status === "ยกเลิก";
  const rows = all.filter(o => tab === "active" ? !isDone(o) : isDone(o));
  const selO = sel ? all.find(o => o.orderId === sel) : null;
  useEffectOO(() => { if (selO && selO.newSlip) ooPatch(selO.orderId, { newSlip: false }); }, [sel]);

  const setStatus = (o, status) => {
    const next = { ...o, status };
    ooPatch(o.orderId, { status });
    ooMirror(next);
    refresh();
  };

  return (
    <>
      <PageHead title="🛒 ออเดอร์ออนไลน์" sub={`งานสั่งตัดจากหน้าเว็บ triples-creative.com/order · ${all.filter(o => !isDone(o)).length} งานเปิดอยู่${lastPull ? " · เช็คล่าสุด " + lastPull.toLocaleTimeString("th-TH") : ""}`}
        right={<>
          <Btn onClick={() => setShowCfg(true)}>⚙️ ตั้งค่าเว็บสั่งตัด</Btn>
          <Btn kind="primary" onClick={pull} disabled={busy}>{busy ? "กำลังเช็ค…" : "🔄 เช็คออเดอร์ใหม่"}</Btn>
        </>}/>
      <div style={{display: "flex", gap: 8, marginBottom: 12}}>
        <Btn size="sm" kind={tab === "active" ? "primary" : "ghost"} onClick={() => setTab("active")}>กำลังดำเนินการ</Btn>
        <Btn size="sm" kind={tab === "done" ? "primary" : "ghost"} onClick={() => setTab("done")}>จบแล้ว</Btn>
      </div>
      <div style={{display: "flex", flexDirection: "column", gap: 10}}>
        {rows.map(o => (
          <div key={o.orderId} onClick={() => setSel(o.orderId)}
            style={{display: "flex", gap: 12, alignItems: "center", flexWrap: "wrap", border: "1px solid var(--line)", borderLeft: "5px solid #0f766e", borderRadius: 12, background: "var(--surface)", padding: "11px 15px", cursor: "pointer"}}>
            <b className="mono" style={{fontSize: 14.5, color: "#0f766e"}}>{o.orderId}</b>
            <OOStatusChip s={o.status}/>
            <span style={{fontSize: 13, fontWeight: 600}}>{(o.contact || {}).name}</span>
            <span style={{fontSize: 12.5, color: "var(--ink-3)", flex: 1, minWidth: 120, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{o.specText}</span>
            {(((o.slipRows || []).length > 0) || o.hasSlip) && <span style={{fontSize: 11.5, fontWeight: 800, color: o.newSlip ? "#dc2626" : "#7c3aed"}}>🧾 สลิป {(o.slipRows || []).length + (o.hasSlip ? 1 : 0)}{o.newSlip ? " ใหม่!" : ""}</span>}
            {(o.price || {}).total ? <b style={{fontSize: 14.5}}>{Number(o.price.total).toLocaleString("th-TH")} ฿</b> : <span style={{fontSize: 11.5, color: "var(--warning)", fontWeight: 700}}>รอตีราคา</span>}
            <span style={{fontSize: 11, color: "var(--ink-4)"}}>{o.at ? new Date(o.at).toLocaleString("th-TH", { dateStyle: "short", timeStyle: "short" }) : ""}</span>
          </div>
        ))}
        {rows.length === 0 && <div style={{padding: 46, textAlign: "center", color: "var(--ink-3)"}}>ยังไม่มีออเดอร์{tab === "active" ? "ที่กำลังดำเนินการ" : "ที่จบแล้ว"} — ลูกค้าสั่งได้ที่ <b>triples-creative.com/order</b></div>}
      </div>

      {selO && (
        <Drawer open wide title={`🛒 ${selO.orderId} · ${(selO.contact || {}).name || ""}`} onClose={() => setSel(null)}
          footer={<div style={{display: "flex", gap: 8, flexWrap: "wrap", width: "100%"}}>
            {!selO.projectCode && <Btn kind="primary" onClick={() => {
              const r = ooAccept(selO);
              ooPatch(selO.orderId, { ...r, status: "กำลังตรวจแบบ" });
              ooMirror({ ...selO, status: "กำลังตรวจแบบ" });
              window.toast && window.toast(`✅ สร้าง ${r.code} + ${r.woNo} แล้ว`);
              refresh();
            }}>✅ รับออเดอร์ → สร้างใบสั่งงาน</Btn>}
            {selO.projectCode && <Btn onClick={() => { setSel(null); navigate && navigate("projects"); }}>📁 เปิดโปรเจกต์ {selO.projectCode}</Btn>}
            <span style={{marginLeft: "auto"}}/>
            <Btn onClick={() => setSel(null)}>ปิด</Btn>
          </div>}>
          <div style={{display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 12}}>
            {[...OO_STATUSES, ...OO_SPECIAL].map(s => (
              <button key={s} onClick={() => setStatus(selO, s)}
                style={{padding: "5px 12px", borderRadius: 999, cursor: "pointer", fontFamily: "inherit", fontSize: 12, fontWeight: 700,
                  border: selO.status === s ? "2px solid #0f766e" : "1px solid var(--line)",
                  background: selO.status === s ? "rgba(15,118,110,0.1)" : "var(--surface)",
                  color: OO_SPECIAL.includes(s) ? "var(--danger)" : "var(--ink-1)"}}>{s}</button>
            ))}
          </div>
          <div style={{fontSize: 11.5, color: "var(--ink-3)", marginBottom: 12}}>กดสถานะ = ลูกค้าเห็นทันทีที่ลิงก์ติดตาม · สถานะ "กำลังผลิต" จะขยับเป็น "ผลิตเสร็จ" เองเมื่อการ์ดในใบสั่งงานเสร็จครบ</div>

          <div style={{border: "1px solid var(--line)", borderLeft: "5px solid #0e7490", borderRadius: 10, padding: "10px 14px", marginBottom: 10, background: "rgba(14,116,144,0.05)"}}>
            <div style={{fontWeight: 800, fontSize: 12.5, marginBottom: 4}}>👤 ลูกค้า</div>
            <div style={{fontSize: 13.5}}>{(selO.contact || {}).name} · ☎️ <b className="mono">{(selO.contact || {}).phone}</b>{(selO.contact || {}).line ? <> · LINE: {(selO.contact || {}).line}</> : null}</div>
            <div style={{fontSize: 12.5, color: "var(--ink-2)", marginTop: 2}}>
              {(selO.contact || {}).ship === "ship" ? "🚚 จัดส่ง: " + ((selO.contact || {}).addr || "-") : "🏭 มารับเองที่โรงงาน"}
              {(selO.contact || {}).note ? <div>📝 {(selO.contact || {}).note}</div> : null}
            </div>
          </div>

          <div style={{border: "1px solid var(--line)", borderLeft: "5px solid #b45309", borderRadius: 10, padding: "10px 14px", marginBottom: 10, background: "rgba(180,83,9,0.05)"}}>
            <div style={{fontWeight: 800, fontSize: 12.5, marginBottom: 4}}>📐 สเปคงาน</div>
            <div style={{fontSize: 13.5}}>{selO.specText}</div>
            {(selO.price || {}).total ? <div style={{fontSize: 14, marginTop: 4}}>💰 ราคาบนเว็บ: <b>{Number(selO.price.total).toLocaleString("th-TH")} ฿</b> · มัดจำ {Number(selO.price.deposit || 0).toLocaleString("th-TH")} ฿</div> : null}
            {(selO.spec || {}).desc ? <div style={{fontSize: 13, marginTop: 4, whiteSpace: "pre-wrap"}}>{(selO.spec || {}).desc}</div> : null}
          </div>

          <OOOrderFiles rowId={selO.rowId}/>
          <OOSlips rowIds={selO.slipRows}/>
        </Drawer>
      )}

      {showCfg && <OOConfigModal onClose={() => setShowCfg(false)}/>}
    </>
  );
}

// ── ตั้งค่าเว็บสั่งตัด: เผยแพร่เรต (ปลอดภัย — รวมโสหุ้ย+กำไรเป็น factor เดียว) + ช่องทางชำระ ──
function OOConfigModal({ onClose }) {
  const { Btn, Drawer } = window.UI;
  const rates = (window.lsRead ? window.lsRead("sss-price-rates", {}) : {}) || {};
  const saved = (window.lsRead ? window.lsRead("sss-order-config-local", {}) : {}) || {};
  const [f, setF] = useStateOO({
    promptpayId: saved.promptpayId || "", promptpayName: saved.promptpayName || "TRIPLES CREATIVE",
    bankText: saved.bankText || "", depositPct: saved.depositPct || 50,
    kshopQr: saved.kshopQr || "", kshopName: saved.kshopName || "",
    minCharge: saved.minCharge != null ? saved.minCharge : 200,
    shipBase: saved.shipBase != null ? saved.shipBase : 50,
    shipPerKg: saved.shipPerKg != null ? saved.shipPerKg : 10,
    shipPerKm: saved.shipPerKm != null ? saved.shipPerKm : 0.45,
  });
  const [busy, setBusy] = useStateOO(false);
  const publish = async () => {
    setBusy(true);
    const cfg = {
      matPrices: rates.matPrices || undefined,
      machineRate: rates.machineRate, laserW: rates.laserW, priceMode: rates.priceMode, cutBase: rates.cutBase,
      bendBase: rates.bendBase, setupBase: rates.setupBase, partHandle: rates.partHandle, scrapPct: rates.scrapPct,
      factor: (1 + (Number(rates.overheadPct) || 15) / 100) * (1 + (Number(rates.margin) || 20) / 100),
      minCharge: Number(f.minCharge) || 200,   // ขั้นต่ำของ "เว็บ" ตั้งแยกจากหน้าคำนวณภายใน
      minChargeOn: true,
      ship: { base: Number(f.shipBase) || 0, perKg: Number(f.shipPerKg) || 0, perKm: Number(f.shipPerKm) || 0, oversizeMM: 1500, oversizeFee: 300 },
      depositPct: Number(f.depositPct) || 50,
      promptpayId: f.promptpayId.trim(), promptpayName: f.promptpayName.trim(), bankText: f.bankText.trim(),
      kshopQr: f.kshopQr || "", kshopName: (f.kshopName || "").trim(),
      publishedAt: new Date().toISOString(),
    };
    Object.keys(cfg).forEach(k => { if (cfg[k] === undefined) delete cfg[k]; });
    try {
      const c = ooClient();
      await c.from("public_store").upsert([{ key: "order-config", data: cfg, updated_at: new Date().toISOString() }], { onConflict: "key" });
      if (window.lsSyncSet) window.lsSyncSet("sss-order-config-local", { ...f, publishedAt: cfg.publishedAt });
      _ooCfgCache = { ...f };
      window.toast && window.toast("✅ เผยแพร่เรต+ช่องทางชำระขึ้นเว็บแล้ว");
      onClose();
    } catch (e) {
      window.toast && window.toast("⚠️ เผยแพร่ไม่สำเร็จ: " + (e.message || e));
    }
    setBusy(false);
  };
  return (
    <Drawer open title="⚙️ ตั้งค่าเว็บสั่งตัดออนไลน์" onClose={onClose}
      footer={<div style={{display: "flex", justifyContent: "space-between", width: "100%"}}>
        <span style={{fontSize: 11.5, color: "var(--ink-3)", alignSelf: "center"}}>{saved.publishedAt ? "เผยแพร่ล่าสุด " + new Date(saved.publishedAt).toLocaleString("th-TH") : "ยังไม่เคยเผยแพร่ — เว็บใช้เรตเริ่มต้น"}</span>
        <Btn kind="primary" onClick={publish} disabled={busy}>{busy ? "กำลังเผยแพร่…" : "🌐 เผยแพร่ขึ้นเว็บ"}</Btn>
      </div>}>
      <div style={{fontSize: 12.5, color: "var(--ink-2)", lineHeight: 1.7, marginBottom: 12, background: "rgba(15,118,110,0.06)", borderRadius: 9, padding: "9px 12px"}}>
        ระบบดึง<b>เรตจากหน้า "คำนวณราคาตัด/พับ"</b> (ราคาวัสดุ/เรตเครื่อง/ค่าพับ ฯลฯ) มาเผยแพร่ให้เว็บอัตโนมัติ
        โดยรวม โสหุ้ย+กำไร เป็นตัวคูณเดียว — <b>คนดูหน้าเว็บไม่มีทางรู้ว่ากำไรเท่าไหร่</b> · แก้เรตแล้วกดเผยแพร่ซ้ำทุกครั้ง
      </div>
      <div className="field"><label>📱 PromptPay (เบอร์มือถือ หรือเลขภาษี 13 หลัก) — เว้นว่าง = ไม่แสดง QR</label>
        <input className="input mono" value={f.promptpayId} onChange={e => setF({ ...f, promptpayId: e.target.value })} placeholder="เช่น 0812345678"/></div>
      <div className="field"><label>ชื่อบัญชี PromptPay</label>
        <input className="input" value={f.promptpayName} onChange={e => setF({ ...f, promptpayName: e.target.value })}/></div>
      <div className="field"><label>🏦 ข้อมูลบัญชีธนาคาร (แสดงคู่กับ QR)</label>
        <textarea className="textarea" value={f.bankText} onChange={e => setF({ ...f, bankText: e.target.value })} placeholder="เช่น กสิกรไทย 123-4-56789-0 บจก.ทริปเปิ้ลเอส ครีเอทีฟ"/></div>
      <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8}}>
        <div className="field"><label>มัดจำเริ่มงาน (%)</label>
          <input className="input" type="number" min="0" max="100" value={f.depositPct} onChange={e => setF({ ...f, depositPct: e.target.value })}/></div>
        <div className="field"><label>ราคาขั้นต่ำต่อออเดอร์ (฿)</label>
          <input className="input" type="number" min="0" value={f.minCharge} onChange={e => setF({ ...f, minCharge: e.target.value })}/></div>
      </div>
      <div className="field" style={{border: "1px solid var(--line)", borderRadius: 9, padding: "9px 11px", background: "var(--surface-2)"}}>
        <label style={{fontWeight: 800}}>🚚 สูตรค่าจัดส่ง (ประมาณจาก น้ำหนัก + ระยะทางจากมหาสารคาม · ชิ้นเกิน 150ซม. +300)</label>
        <div style={{display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8}}>
          <div className="field" style={{marginBottom: 0}}><label>เริ่มต้น (฿)</label>
            <input className="input" type="number" value={f.shipBase} onChange={e => setF({ ...f, shipBase: e.target.value })}/></div>
          <div className="field" style={{marginBottom: 0}}><label>฿/กก.</label>
            <input className="input" type="number" step="any" value={f.shipPerKg} onChange={e => setF({ ...f, shipPerKg: e.target.value })}/></div>
          <div className="field" style={{marginBottom: 0}}><label>฿/กม.</label>
            <input className="input" type="number" step="any" value={f.shipPerKm} onChange={e => setF({ ...f, shipPerKm: e.target.value })}/></div>
        </div>
      </div>
      <div className="field"><label>💚 QR ร้าน K PLUS shop (แคปจากแอป K PLUS shop → อัพโหลด — โชว์คู่กับ PromptPay)</label>
        <div style={{display: "flex", gap: 10, alignItems: "center"}}>
          {f.kshopQr && <img src={f.kshopQr} style={{width: 84, borderRadius: 9, border: "1px solid var(--line)"}}/>}
          <window.UI.Btn size="sm" onClick={() => document.getElementById("ooKshopFile").click()}>{f.kshopQr ? "เปลี่ยนรูป QR" : "📷 อัพโหลดรูป QR"}</window.UI.Btn>
          {f.kshopQr && <window.UI.Btn size="sm" onClick={() => setF({ ...f, kshopQr: "" })}>ลบ</window.UI.Btn>}
          <input id="ooKshopFile" type="file" accept="image/*" style={{display: "none"}} onChange={e => {
            const file = e.target.files[0]; e.target.value = "";
            if (!file) return;
            const rd = new FileReader();
            rd.onload = () => {
              const img = new Image();
              img.onload = () => {
                const sc = Math.min(1, 700 / Math.max(img.width, img.height));
                const cv = document.createElement("canvas"); cv.width = Math.round(img.width * sc); cv.height = Math.round(img.height * sc);
                cv.getContext("2d").drawImage(img, 0, 0, cv.width, cv.height);
                setF(p => ({ ...p, kshopQr: cv.toDataURL("image/jpeg", 0.85) }));
              };
              img.src = rd.result;
            };
            rd.readAsDataURL(file);
          }}/>
        </div>
      </div>
      <div className="field"><label>ชื่อร้านใน K PLUS shop</label>
        <input className="input" value={f.kshopName || ""} onChange={e => setF({ ...f, kshopName: e.target.value })} placeholder="เช่น ร้าน TRIPLES CREATIVE"/></div>
    </Drawer>
  );
}

window.OnlineOrdersPage = OnlineOrdersPage;
