/* global React, I, UI */
// ═══ การ์ดงานในใบสั่งงาน — 1 การ์ด = 1 งาน ═══════════════════════════════
// แต่ละใบสั่งงานประกอบด้วยการ์ดงานเรียงตามลำดับ เลือกประเภทได้:
//   ✂️ งานตัด · 📐 งานพับ · 🌀 งานม้วน · 🎨 งานทำสี · 🔧 กำหนดเอง
// การ์ดที่มีรายการชิ้นงาน (ตัด/พับ/ม้วน/กำหนดเอง) แนบรูปแบบงานได้เหมือนใบสั่งตัดเดิม
// ทุกการ์ดจองคิวเครื่องจักรได้ → ขึ้นบอร์ด "คิวงานเครื่องจักร" อัตโนมัติ (id คงที่ กันซ้ำ/ค้าง)
const { useState: useStateWC } = React;

// แต่ละประเภทงานมี "อัตลักษณ์" ของตัวเอง — ช่อง extra ต่อชิ้นงาน (องศาพับ/สี/วิธีตกแต่ง ฯลฯ) ขึ้นใบพิมพ์ด้วย
const WC_TYPES = {
  cut:    { label: "งานตัด",        emoji: "✂️", color: "#b91c1c", bg: "rgba(185,28,28,0.07)",  items: true,  photoLabel: "แบบงานตัด",     itemPh: "ชื่อชิ้นงานที่จะตัด — เลือกจากรายการส่งมอบ หรือพิมพ์เอง",        attach: "แนบแบบ", pathPh: "📁 PATH ไฟล์แบบตัด เช่น SSS-FILES/JOBDATA/2026/...",     detailHint: "เช่น ตัดตามเส้นแบบ เผื่อขอบ 2 มม. ระวังรอยขีดผิว" },
  bend:   { label: "งานพับ/ม้วน",   emoji: "📐", color: "#b45309", bg: "rgba(180,83,9,0.07)",   items: true,  photoLabel: "แบบงานพับ/ม้วน", itemPh: "ชื่อชิ้นงานที่จะพับ/ม้วน — เลือกจากรายการส่งมอบ หรือพิมพ์เอง",   attach: "แนบแบบ", noPath: true, detailHint: "อธิบายวิธีพับ/ม้วน เช่น พับ 45° ตามเส้นประ 2 จุด · ม้วนรัศมี R50",
            extra: { label: "องศา/สเปคพับ-ม้วน", ph: "เช่น พับ 45° 2 จุด · ม้วน R50", quick: ["พับ 90°", "พับ 45°", "ม้วน"] } },
  roll:   { label: "งานม้วน",       emoji: "🌀", color: "#0e7490", bg: "rgba(14,116,144,0.07)", items: true,  photoLabel: "แบบงานม้วน",    itemPh: "ชื่อชิ้นงานที่จะม้วน — เลือกจากรายการส่งมอบ หรือพิมพ์เอง",       attach: "แนบแบบ", noPath: true,    detailHint: "เช่น ม้วนรัศมี R50 ตลอดแนว · ม้วนครึ่งวงกลม Ø200",
            extra: { label: "องศา/สเปคม้วน", ph: "เช่น ม้วน R50 ตลอดแนว", quick: [] } },
  weld:   { label: "งานเชื่อม/ประกอบ", emoji: "🔩", color: "#475569", bg: "rgba(71,85,105,0.08)", items: true, photoLabel: "แบบงานเชื่อม/ประกอบ", itemPh: "ชื่อชิ้นงานที่จะเชื่อม/ประกอบ — เลือกจากรายการส่งมอบ หรือพิมพ์เอง", attach: "แนบแบบ", noPath: true, detailHint: "เช่น เชื่อมเต็มแนว เก็บตะเข็บเรียบ · ประกอบตามแบบ",
            extra: { label: "รายละเอียดเชื่อม/ประกอบ", ph: "เช่น เชื่อมเต็มแนว · สปอตทุก 10 ซม.", quick: ["เชื่อม", "ประกอบ"] } },
  paint:  { label: "งานทำสี",       emoji: "🎨", color: "#7c3aed", bg: "rgba(124,58,237,0.07)", items: true,  photoLabel: "ตัวอย่างสี/ผิวงาน", itemPh: "ชื่อชิ้นงานที่จะทำสี — เลือกจากรายการส่งมอบ หรือพิมพ์เอง",      attach: "แนบรูปสี", noPath: true, detailHint: "เช่น พ่นสีดำด้าน พาวเดอร์โค้ท · เตรียมผิวด้วยการพ่นทราย",
            extra: { label: "สีของชิ้นนี้", ph: "เช่น ดำด้าน · ขาวเงา · พาวเดอร์โค้ทเทา", quick: [] } },
  decor:  { label: "งานตกแต่ง",     emoji: "✨", color: "#db2777", bg: "rgba(219,39,119,0.07)", items: true,  photoLabel: "รูปงานตกแต่ง",  itemPh: "ชิ้นงานที่จะตกแต่ง (เจียร์/ขัด/อื่นๆ)",              attach: "แนบรูป", noPath: true,  detailHint: "เช่น เจียร์ลบคมทุกขอบ · ขัดเงาทั้งชิ้น",
            extra: { label: "วิธีตกแต่ง", ph: "เจียร์ / ขัด / อื่นๆ ระบุเอง", quick: ["เจียร์", "ขัด"] } },
  deliver:{ label: "งานส่งของ",      emoji: "🚚", color: "#15803d", bg: "rgba(21,128,61,0.07)",  items: true,  photoLabel: "รูปของที่จะส่ง", itemPh: "ของที่จะส่ง — เลือกจากรายการส่งมอบ หรือพิมพ์เอง",               attach: "แนบรูป", noPath: true, detailHint: "จุดส่ง/ผู้รับ/เบอร์ติดต่อ เช่น ส่งหน้างานลูกค้า คุณเอ 081-xxx-xxxx", deliver: true },
  custom: { label: "กำหนดเอง",      emoji: "🔧", color: "#57534e", bg: "var(--surface-2)",      items: true,  photoLabel: "รูปประกอบ",     itemPh: "ชื่อชิ้นงาน / สิ่งที่ต้องทำ",                          attach: "แนบรูป", noPath: true,     detailHint: "อธิบายงานที่ต้องทำ" },
};
// เมนูเพิ่มการ์ด (ม้วนรวมกับพับแล้ว — การ์ดม้วนเก่ายังแสดง/พิมพ์ได้ปกติ)
const WC_ORDER = ["cut", "bend", "weld", "paint", "decor", "deliver", "custom"];
const WC_STATUS = ["รอทำ", "กำลังทำ", "เสร็จแล้ว"];
const wcType = (t) => WC_TYPES[t] || WC_TYPES.custom;
const wcUid = () => "C" + Date.now().toString(36) + Math.random().toString(36).slice(2, 5);

// ── ตัวช่วยที่ยืมจากโมดูลโปรเจกต์ (โหลดก่อนไฟล์นี้เสมอ) ──
const wcThai = (iso) => (window.ProjX && window.ProjX.pxThaiDate ? window.ProjX.pxThaiDate(iso) : iso || "—");
const wcToday = () => (window.ProjX && window.ProjX.pxTodayISO ? window.ProjX.pxTodayISO() : new Date().toISOString().slice(0, 10));
function wcLS(key, def) { return (window.lsRead ? window.lsRead(key, def) : def); }
function wcLSSet(key, val) { if (window.lsSyncSet) window.lsSyncSet(key, val); else { try { localStorage.setItem(key, JSON.stringify(val)); } catch (e) {} } }

// แบบงานเป็นภาพลายเส้น → เก็บ PNG (ไม่บีบ JPEG กันคราบรอบเส้นตอนพิมพ์)
function wcResize(file, max) {
  return new Promise(resolve => {
    const r = new FileReader();
    r.onload = () => {
      const img = new Image();
      img.onload = () => {
        const sc = Math.min(1, max / Math.max(img.width, img.height));
        const c = document.createElement("canvas");
        c.width = Math.max(1, Math.round(img.width * sc));
        c.height = Math.max(1, Math.round(img.height * sc));
        c.getContext("2d").drawImage(img, 0, 0, c.width, c.height);
        resolve(c.toDataURL("image/png"));
      };
      img.onerror = () => resolve(null);
      img.src = r.result;
    };
    r.onerror = () => resolve(null);
    r.readAsDataURL(file);
  });
}

// แปลงใบสั่งตัดเดิม → การ์ดงานตัด (ข้อมูลเก่าไม่หาย ใช้ต่อได้ทันที)
function wcFromCutOrder(co) {
  return {
    id: wcUid(), type: "cut", title: "งานตัด · " + (co.no || ""),
    detail: co.note || "", status: co.status || "รอทำ",
    assigneeId: co.assigneeId || "", due: co.due || "",
    machineId: co.machineId || "", date: co.cutDate || "", start: co.cutStart || "", end: co.cutEnd || "",
    items: (co.items || []).map(it => ({
      id: wcUid(), name: it.name || "", material: it.material || "", path: it.path || "",
      qty: it.qty || 1, unit: it.unit || "ชุด", photos: (it.photos || []).slice(),
    })),
    fromCut: co.no,
  };
}
const wcNormalize = (c) => ({
  id: c.id || wcUid(), type: c.type || "custom", title: c.title || "", detail: c.detail || "",
  status: c.status || "รอทำ", assigneeId: c.assigneeId || "", assigneeName: c.assigneeName || "", due: c.due || "",
  helpers: (c.helpers || []).map(h => ({ id: h.id || "", name: h.name || "" })).filter(h => h.id || h.name),
  ack: c.ack || null, issue: c.issue || null, doneItems: c.doneItems || [], stOrd: c.stOrd != null ? c.stOrd : null,
  machineId: c.machineId || "", date: c.date || "", start: c.start || "", end: c.end || "",
  place: c.place || "", receiver: c.receiver || "", phone: c.phone || "",
  items: (c.items || []).map(it => ({ id: it.id || wcUid(), name: it.name || "", material: it.material || "",
    path: it.path || "", spec: it.spec || "", qty: it.qty != null ? it.qty : 1, unit: it.unit || "ชุด", photos: (it.photos || []).slice() })),
});

// ── ซิงค์คิวเครื่องจักร: 1 การ์ด = 1 งานบนบอร์ด · id คงที่ MQC-<เลขใบ>-<idการ์ด> ──
// แก้การ์ด = ย้ายคิวตาม · ปิดจอง/ลบการ์ด = ถอนคิวออกให้เอง (ไม่มีงานผีค้างบอร์ด)
function wcSyncQueue(woNo, cards, project) {
  const QK = "sss-machine-queue";
  const all = wcLS(QK, []) || [];
  const prefix = "MQC-" + woNo + "-";
  let q = all.filter(j => !(j && typeof j.id === "string" && j.id.indexOf(prefix) === 0));
  (cards || []).forEach((c, idx) => {
    if (c.type === "deliver") return;             // งานส่งของไปหน้าส่งของประจำวัน ไม่ขึ้นบอร์ดเครื่องจักร
    if (!c.machineId || !c.date) return;
    const t = wcType(c.type);
    const first = (c.items || []).find(x => x.name);
    // ค่าที่จอสถานีบันทึกไว้กับงานเดิม ต้องรอด: เบิกแผ่น/ลำดับลากคิว/ติดปัญหา/ชิ้นที่ตัดแล้ว
    const keep = all.find(j => j && j.id === prefix + c.id) || {};
    q = [{
      matDone: keep.matDone || null, ord: keep.ord, issue: keep.issue || null, doneItems: keep.doneItems || [],
      id: prefix + c.id,
      title: `${t.emoji} ${woNo} · ${c.title || t.label}${first ? ` — ${first.name}` : ""}`,
      project: project ? project.code : "", machineId: c.machineId, date: c.date,
      start: c.start || "", end: c.end || "",
      status: c.status === "เสร็จแล้ว" ? "เสร็จ" : c.status === "กำลังทำ" ? "กำลังทำ" : "รอคิว",
      assignee: c.assigneeName || "", note: `ใบสั่งงาน ${woNo} · การ์ดที่ ${idx + 1} · ${t.label}`,
    }, ...q];
  });
  wcLSSet(QK, q);
}
// ── ลิงค์การ์ด "งานส่งของ" → ส่งของประจำวันอัตโนมัติ · id คงที่ WODD-<เลขใบ>-<idการ์ด> ──
// แก้การ์ด = รายการส่งของย้ายตาม · ลบการ์ด/ใบ = ถอนรายการที่ยังไม่ส่ง (ที่ส่งแล้วเก็บไว้เป็นประวัติ)
function wcSyncDeliveries(woNo, cards, project) {
  const D = window.SSSData; if (!D) return;
  const list = Array.isArray(D.DailyDeliveries) ? D.DailyDeliveries : (D.DailyDeliveries = []);
  const prefix = "WODD-" + woNo + "-";
  const wanted = new Set();
  (cards || []).forEach(c => {
    if (c.type !== "deliver" || !c.date) return;
    const id = prefix + c.id;
    wanted.add(id);
    const old = list.find(d => d && d.id === id);
    if (old && old.status === "ส่งแล้ว") return;   // ส่งสำเร็จแล้ว — ไม่แตะประวัติ
    const rec = {
      id, no: old && old.no ? old.no : ("DD-" + woNo.replace(/^WO-/, "") + "-" + ((cards.filter(x => x.type === "deliver").indexOf(c)) + 1)),
      date: c.date, time: c.start || "",
      customer: (project && project.customer) || "", project: project ? project.code : "",
      detail: [c.detail || c.title || "งานส่งของ", c.place ? "📍 " + c.place : "", (c.receiver || c.phone) ? ("👤 " + (c.receiver || "") + (c.phone ? " ☎️ " + c.phone : "")).trim() : ""].filter(Boolean).join("\n"),
      place: c.place || "",
      items: (c.items || []).filter(x => x.name).map(x => ({ name: x.name, qty: Number(x.qty) || 1, unit: x.unit || "ชิ้น", photo: (x.photos || [])[0] || null })),
      status: old ? old.status : "รอจัดส่ง",
      photosBefore: old ? old.photosBefore : [], photosAfter: old ? old.photosAfter : [],
      signature: old ? old.signature : null, receiverName: old ? old.receiverName : (c.receiver || ""),
      fromWO: woNo,
    };
    const i = list.findIndex(d => d && d.id === id);
    if (i >= 0) list[i] = { ...list[i], ...rec }; else list.unshift(rec);
  });
  // ถอนรายการของใบนี้ที่การ์ดถูกลบ/เลิกนัด (เฉพาะที่ยังไม่ส่ง)
  D.DailyDeliveries = list.filter(d => !(d && typeof d.id === "string" && d.id.indexOf(prefix) === 0 && !wanted.has(d.id) && d.status !== "ส่งแล้ว"));
  try { window.SSSSync && window.SSSSync.queue && window.SSSSync.queue(); } catch (e) {}
  try { window.dispatchEvent(new Event("sss-deliveries-changed")); } catch (e) {}
}
function wcRemoveDeliveries(woNo) {
  const D = window.SSSData; if (!D || !Array.isArray(D.DailyDeliveries)) return;
  const prefix = "WODD-" + woNo + "-";
  const before = D.DailyDeliveries.length;
  D.DailyDeliveries = D.DailyDeliveries.filter(d => !(d && typeof d.id === "string" && d.id.indexOf(prefix) === 0 && d.status !== "ส่งแล้ว"));
  if (D.DailyDeliveries.length !== before) {
    try { window.SSSSync && window.SSSSync.queue && window.SSSSync.queue(); } catch (e) {}
    try { window.dispatchEvent(new Event("sss-deliveries-changed")); } catch (e) {}
  }
}
function wcRemoveQueue(woNo) {
  const QK = "sss-machine-queue";
  const all = wcLS(QK, []) || [];
  const prefix = "MQC-" + woNo + "-";
  const next = all.filter(j => !(j && typeof j.id === "string" && j.id.indexOf(prefix) === 0));
  if (next.length !== all.length) wcLSSet(QK, next);
}

// ── รูปพนักงานสี่เหลี่ยมมุมมน (รูปจาก HR → โปรไฟล์แชท → ตัวย่อ) ──
function WCEmpAvatar({ e, size = 48 }) {
  const phs = wcLS("sss-employee-photos", {}) || {};
  const prof = (window.ChatProfiles && e && e.name) ? window.ChatProfiles.get(e.name) : null;
  const photo = (e && e.id && phs[e.id]) || (prof && prof.avatar) || "";
  const color = (prof && prof.color) || "var(--accent)";
  const r = Math.round(size * 0.22);
  return photo
    ? <img src={photo} alt="" style={{width: size, height: size, borderRadius: r, objectFit: "cover", border: `2px solid ${color}`, flexShrink: 0}}/>
    : <div style={{width: size, height: size, borderRadius: r, background: color, color: "#fff", display: "grid", placeItems: "center", fontWeight: 800, fontSize: Math.round(size * 0.32), flexShrink: 0}}>{String((e && e.name) || "?").slice(0, 2)}</div>;
}

// ── เลือกผู้รับผิดชอบจากรูป — ลิสต์ [รูปสี่เหลี่ยม | ชื่อ+ตำแหน่ง] ตามแบบที่ผู้ใช้ร่าง ──
// เรียงคนที่ถูกเลือกบ่อย (จากใบสั่งงาน/การ์ดทั้งระบบ) ขึ้นก่อน
function WCEmpPick({ emps, value, onPick, onClose }) {
  const [q, setQ] = useStateWC("");
  const freq = {};
  try {
    Object.values((window.ProjX && window.ProjX.pxLoad) ? window.ProjX.pxLoad() : {}).forEach(x =>
      (x.workOrders || []).forEach(w => {
        (w.assigneeIds || []).forEach(id => { freq[id] = (freq[id] || 0) + 1; });
        (w.cards || []).forEach(c => {
          if (c.assigneeId) freq[c.assigneeId] = (freq[c.assigneeId] || 0) + 1;
          (c.helpers || []).forEach(h => { if (h.id) freq[h.id] = (freq[h.id] || 0) + 1; });
        });
      }));
  } catch (e) {}
  const needle = q.trim().toLowerCase();
  const list = (emps || [])
    .filter(e => !needle || (e.name + " " + (e.role || "") + " " + (e.dept || "")).toLowerCase().includes(needle))
    .slice().sort((a, b) => (freq[b.id] || 0) - (freq[a.id] || 0));
  const row = { display: "flex", alignItems: "center", gap: 14, padding: "11px 16px", cursor: "pointer", borderBottom: "1px solid var(--line)" };
  return (
    <div onClick={e => { if (e.target === e.currentTarget) onClose(); }}
      style={{position: "fixed", inset: 0, zIndex: 460, background: "rgba(12,10,9,0.6)", backdropFilter: "blur(2px)", display: "flex", alignItems: "center", justifyContent: "center", padding: 16}}>
      <div style={{background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 14, width: "100%", maxWidth: 540, maxHeight: "88vh", display: "flex", flexDirection: "column", overflow: "hidden", boxShadow: "var(--shadow-lg)"}}>
        <div style={{padding: "13px 16px", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 10}}>
          <b style={{fontSize: 14.5}}>👷 เลือกผู้รับผิดชอบงานนี้</b>
          <span style={{fontSize: 11.5, color: "var(--ink-4)"}}>คนที่เลือกบ่อยขึ้นก่อน</span>
          <button className="icon-btn" style={{marginLeft: "auto"}} onClick={onClose}><I.close size={14}/></button>
        </div>
        <div style={{padding: "10px 16px 6px"}}>
          <input className="input" placeholder="🔍 ค้นหาชื่อ / ตำแหน่ง…" value={q} onChange={e => setQ(e.target.value)} autoFocus/>
        </div>
        <div style={{overflowY: "auto"}}>
          <div style={{...row, color: "var(--ink-3)"}} onClick={() => onPick(null)}
            onMouseEnter={e => { e.currentTarget.style.background = "var(--surface-2)"; }} onMouseLeave={e => { e.currentTarget.style.background = ""; }}>
            <div style={{width: 56, height: 56, borderRadius: 12, border: "1.5px dashed var(--line-strong)", display: "grid", placeItems: "center", fontSize: 20, flexShrink: 0}}>—</div>
            <div style={{fontSize: 14, fontWeight: 600}}>ยังไม่ระบุ</div>
          </div>
          {list.map(e => {
            const sel = value && e.id === value;
            return (
              <div key={e.id} style={{...row, background: sel ? "rgba(59,130,246,0.09)" : ""}}
                onClick={() => onPick(e)}
                onMouseEnter={ev => { if (!sel) ev.currentTarget.style.background = "var(--surface-2)"; }}
                onMouseLeave={ev => { if (!sel) ev.currentTarget.style.background = ""; }}>
                <WCEmpAvatar e={e} size={56}/>
                <div style={{flex: 1, minWidth: 0}}>
                  <div style={{fontSize: 15, fontWeight: 700}}>{e.name}</div>
                  <div style={{fontSize: 12, color: "var(--ink-3)", marginTop: 2}}>{e.role || e.dept || ""}</div>
                </div>
                {sel && <span style={{width: 24, height: 24, borderRadius: "50%", background: "var(--accent)", color: "var(--accent-ink, #fff)", display: "grid", placeItems: "center", fontSize: 12, fontWeight: 800, flexShrink: 0}}>✓</span>}
              </div>
            );
          })}
          {list.length === 0 && <div style={{padding: 20, textAlign: "center", color: "var(--ink-4)", fontSize: 12.5}}>ไม่พบพนักงานที่ค้นหา</div>}
        </div>
      </div>
    </div>
  );
}

// ── ช่องชื่อชิ้นงานในการ์ด: แนะนำจาก "รายการส่งมอบของใบนี้" เท่านั้น (พิมพ์เองก็ได้) ──
function WCItemNameInput({ value, onChange, onPickWo, woItems, placeholder }) {
  const [open, setOpen] = useStateWC(false);
  const q = String(value || "").trim().toLowerCase();
  const hits = (woItems || []).filter(wi => wi.name && (!q || wi.name.toLowerCase().includes(q)));
  return (
    <div style={{position: "relative"}}>
      <input className="input" style={{fontWeight: 600}} value={value} placeholder={placeholder}
        onChange={e => { onChange(e.target.value); setOpen(true); }}
        onFocus={() => setOpen(true)}
        onBlur={() => setTimeout(() => setOpen(false), 160)}/>
      {open && hits.length > 0 && (
        <div style={{position: "absolute", top: "calc(100% + 3px)", left: 0, width: "min(420px, 74vw)", minWidth: "100%",
          zIndex: 60, background: "var(--surface)", border: "1px solid var(--line-strong)", borderRadius: 9, boxShadow: "0 12px 32px rgba(0,0,0,0.22)", maxHeight: 260, overflowY: "auto"}}>
          <div style={{padding: "5px 11px", fontSize: 10.5, fontWeight: 700, color: "var(--ink-4)", borderBottom: "1px solid var(--line)"}}>📦 ชิ้นงานจากรายการส่งมอบของใบนี้</div>
          {hits.map((wi, k) => (
            <div key={k} onMouseDown={e => { e.preventDefault(); onPickWo(wi); setOpen(false); }}
              style={{display: "flex", gap: 9, alignItems: "center", padding: "8px 11px", cursor: "pointer", borderBottom: k < hits.length - 1 ? "1px solid var(--line)" : "none"}}
              onMouseEnter={e => { e.currentTarget.style.background = "var(--surface-2)"; }}
              onMouseLeave={e => { e.currentTarget.style.background = ""; }}>
              <span style={{fontSize: 13, fontWeight: 600, flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{wi.name}</span>
              <span style={{fontSize: 11.5, color: "var(--ink-3)", flexShrink: 0}}>{wi.qty || 1} {wi.unit || ""}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// ตัวแก้ไขการ์ด (ใช้ในใบสั่งงาน)
// ════════════════════════════════════════════════════════════════════════════
function WCCardEditor({ card, index, total, emps, machines, onChange, onRemove, onMove, defaultOpen, woItems }) {
  const { Btn } = window.UI;
  const t = wcType(card.type);
  const [open, setOpen] = useStateWC(!!defaultOpen);   // เริ่มต้นย่อเป็นแถบสี — ฟอร์มสั้น เห็นภาพรวมทั้งใบ
  const [busy, setBusy] = useStateWC("");
  const [pickEmp, setPickEmp] = useStateWC(false);   // เลือกผู้รับผิดชอบจากรูป
  const [pickHelper, setPickHelper] = useStateWC(false); // เพิ่มผู้ช่วยจากรูป (ได้หลายคน)
  const upd = (k, v) => onChange({ ...card, [k]: v });
  const updItem = (id, k, v) => onChange({ ...card, items: card.items.map(it => it.id === id ? { ...it, [k]: v } : it) });
  const addItem = () => onChange({ ...card, items: [...card.items, { id: wcUid(), name: "", material: "", path: "", qty: 1, unit: (card.items[card.items.length - 1] || {}).unit || "ชุด", photos: [] }] });
  const delItem = (id) => onChange({ ...card, items: card.items.length > 1 ? card.items.filter(it => it.id !== id) : card.items });
  const addPhotos = async (id, e) => {
    const files = [...(e.target.files || [])]; e.target.value = "";
    if (!files.length) return;
    setBusy(`กำลังเตรียมรูป ${files.length} รูป…`);
    const out = [];
    for (const fl of files) { const u = await wcResize(fl, 1600); if (u) out.push(u); }
    setBusy("");
    if (out.length) onChange({ ...card, items: card.items.map(it => it.id === id ? { ...it, photos: [...(it.photos || []), ...out] } : it) });
  };
  const delPhoto = (id, k) => onChange({ ...card, items: card.items.map(it => it.id === id ? { ...it, photos: it.photos.filter((_, x) => x !== k) } : it) });
  // เลือกชิ้นงานจากรายการส่งมอบของใบ — การ์ดไหนทำชิ้นไหนก็ติ้กเอา (ไม่ทำไม่ต้องเลือก)
  const togglePick = (wi) => {
    const nm = (wi.name || "").trim();
    if (!nm) return;
    const victim = card.items.find(x => (x.name || "").trim() === nm);
    if (victim) {
      if (((victim.photos || []).length || (victim.spec || "").trim()) && !window.confirm(`เอา "${nm}" ออกจากการ์ดนี้? แบบ/สเปคที่กรอกไว้ในชิ้นนี้จะหายไป`)) return;
      const left = card.items.filter(x => (x.name || "").trim() !== nm);
      onChange({ ...card, items: left.length ? left : [{ id: wcUid(), name: "", material: "", path: "", spec: "", qty: 1, unit: "ชุด", photos: [] }] });
    } else {
      const blankIdx = card.items.findIndex(x => !(x.name || "").trim() && !(x.photos || []).length);
      // ดึงประวัติจากคลังชิ้นงานมาเติมให้เอง — วัสดุ/PATH/สเปค/รูปแบบ/วิธีทำ แยกตามประเภทการ์ด (บันทึกล่าสุดเป็นหลัก)
      const lf = (window.SSSItemLib && window.SSSItemLib.fill && window.SSSItemLib.fill(nm, card.type)) || null;
      const rec = {
        id: wcUid(), name: nm,
        material: (lf && lf.material) || "",
        path: (lf && lf.path) || "",
        spec: (lf && lf.spec) || "",
        qty: wi.qty != null ? wi.qty : 1, unit: wi.unit || (lf && lf.unit) || "ชิ้น",
        photos: (lf ? lf.photos : []).slice(0, 6),
      };
      if (lf && (rec.material || rec.path || rec.spec || rec.photos.length || lf.detail)) {
        try { window.toast && window.toast(`📚 เติมประวัติ "${nm}" จากคลังให้แล้ว — แก้ได้ตามต้องการ`); } catch (e) {}
      }
      const items2 = blankIdx >= 0 ? card.items.map((x, j) => j === blankIdx ? { ...rec, id: x.id } : x) : [...card.items, rec];
      // วิธีทำของการ์ดยังว่าง → เติมขั้นตอนล่าสุดที่เคยใช้กับชิ้นนี้ในสถานีนี้ให้เลย
      const detail2 = (card.detail || "").trim() ? card.detail : ((lf && lf.detail) || card.detail || "");
      onChange({ ...card, items: items2, detail: detail2 });
    }
  };
  const nPhotos = (card.items || []).reduce((s, it) => s + (it.photos || []).length, 0);

  return (
    <div style={{border: `1px solid var(--line-strong)`, borderLeft: `5px solid ${t.color}`, borderRadius: 11, background: "var(--surface)", overflow: "hidden"}}>
      {/* หัวการ์ด — กดพับ/กางได้ · ตอนย่อเป็นแถบสีทึบมองปราดเดียวรู้ว่ามีงานอะไร */}
      <div style={{display: "flex", alignItems: "center", gap: 9, padding: "9px 11px", cursor: "pointer",
        background: open ? t.bg : `linear-gradient(90deg, ${t.color}, ${t.color}cc)`}} onClick={() => setOpen(v => !v)}>
        <span style={{width: 25, height: 25, borderRadius: "50%", background: open ? t.color : "rgba(255,255,255,0.28)", color: "#fff", display: "grid", placeItems: "center", fontSize: 12, fontWeight: 800, flexShrink: 0}}>{index + 1}</span>
        <span style={{fontSize: 17}}>{t.emoji}</span>
        <div style={{flex: 1, minWidth: 0}}>
          <div style={{fontSize: 13.5, fontWeight: 700, color: open ? t.color : "#fff", textShadow: open ? "none" : "0 1px 2px rgba(0,0,0,0.25)"}}>{card.title || t.label}</div>
          <div style={{fontSize: 11, color: open ? "var(--ink-3)" : "rgba(255,255,255,0.88)"}}>
            {t.label}
            {card.items.filter(x => x.name).length > 0 && ` · ${card.items.filter(x => x.name).length} รายการ`}
            {nPhotos > 0 && ` · ${nPhotos} รูป`}
            {card.machineId && card.date && ` · 🏭 จองคิว ${wcThai(card.date)}`}
          </div>
        </div>
        <span style={{fontSize: 11.5, fontWeight: 700, color: open ? "var(--ink-4)" : "#fff", opacity: open ? 1 : 0.9}}>{open ? "▲ ย่อ" : "▼ กดเพื่อแก้ไข"}</span>
        <div style={{display: "flex", gap: 2}} onClick={e => e.stopPropagation()}>
          <button className="icon-btn" title="เลื่อนขึ้น" onClick={() => onMove(-1)} disabled={index === 0} style={{opacity: index === 0 ? 0.3 : 1, color: open ? undefined : "#fff"}}><I.chevronUp size={13}/></button>
          <button className="icon-btn" title="เลื่อนลง" onClick={() => onMove(1)} disabled={index === total - 1} style={{opacity: index === total - 1 ? 0.3 : 1, color: open ? undefined : "#fff"}}><I.chevronDown size={13}/></button>
          <button className="icon-btn" title="ลบการ์ดนี้" onClick={onRemove} style={open ? undefined : {color: "#fff"}}><I.trash size={13}/></button>
        </div>
      </div>

      {open && (
        <div style={{padding: 11, display: "flex", flexDirection: "column", gap: 9}}>
          <div className="field-row" style={{display: "grid", gridTemplateColumns: "1.4fr 1fr 1fr", gap: 8}}>
            <div className="field"><label>ชื่องาน</label>
              <input className="input" value={card.title} onChange={e => upd("title", e.target.value)} placeholder={t.label + " — ตั้งชื่อให้ช่างเข้าใจ"}/></div>
            <div className="field"><label>ผู้รับผิดชอบ</label>
              {(() => {
                const aEmp = emps.find(e2 => e2.id === card.assigneeId) || (card.assigneeName ? { name: card.assigneeName } : null);
                return (
                  <button type="button" className="input" onClick={() => setPickEmp(true)} title="กดเพื่อเลือกจากรูปพนักงาน"
                    style={{display: "flex", alignItems: "center", gap: 8, cursor: "pointer", textAlign: "left", height: "auto", minHeight: 38, padding: "4px 10px"}}>
                    {aEmp
                      ? <><WCEmpAvatar e={aEmp} size={30}/><span style={{fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{aEmp.name}</span></>
                      : <span style={{color: "var(--ink-4)"}}>👷 เลือกจากรูปพนักงาน…</span>}
                  </button>
                );
              })()}
            </div>
            <div className="field"><label>สถานะ</label>
              <select className="input" value={card.status} onChange={e => upd("status", e.target.value)}>
                {WC_STATUS.map(s => <option key={s}>{s}</option>)}
              </select></div>
          </div>

          <div className="field"><label>🤝 ผู้ช่วยในงานนี้ <span style={{fontWeight: 400, color: "var(--ink-3)"}}>(เพิ่มได้หลายคน — ขึ้นในใบงานพิมพ์ด้วย)</span></label>
            <div style={{display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center"}}>
              {(card.helpers || []).map((h, hi) => (
                <span key={hi} style={{display: "inline-flex", alignItems: "center", gap: 6, padding: "3px 8px 3px 4px", border: "1.5px solid " + t.color + "55", borderRadius: 999, background: "var(--surface-2)", fontSize: 12.5, fontWeight: 600}}>
                  <WCEmpAvatar e={emps.find(e2 => e2.id === h.id) || { name: h.name }} size={24}/>{h.name}
                  <button type="button" title="เอาออก" onClick={() => upd("helpers", (card.helpers || []).filter((_, j) => j !== hi))}
                    style={{border: "none", background: "none", cursor: "pointer", color: "var(--danger)", fontWeight: 800, fontSize: 13, padding: 0, lineHeight: 1}}>✕</button>
                </span>
              ))}
              <button type="button" onClick={() => setPickHelper(true)}
                style={{padding: "5px 12px", borderRadius: 999, cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 700, border: "1.5px dashed " + t.color, background: "var(--surface)", color: t.color}}>➕ เพิ่มผู้ช่วย</button>
            </div>
          </div>

          <div className="field"><label>รายละเอียด / วิธีทำ</label>
            <textarea className="textarea" style={{minHeight: 52}} value={card.detail} onChange={e => upd("detail", e.target.value)} placeholder={t.detailHint}/></div>

          {/* รายการชิ้นงาน + แบบ */}
          <div>
            <div className="label mb" style={{fontSize: 12}}>รายการชิ้นงาน · {t.photoLabel}</div>
            {Array.isArray(woItems) && woItems.length > 0 && (
              <div style={{display: "flex", gap: 6, flexWrap: "wrap", alignItems: "center", marginBottom: 8, padding: "8px 10px", border: "1.5px dashed " + t.color + "66", borderRadius: 9, background: "var(--surface-2)"}}>
                <span style={{fontSize: 11.5, fontWeight: 700, color: "var(--ink-3)"}}>👇 เลือกชิ้นที่ทำในงานนี้ จากรายการส่งมอบ:</span>
                {woItems.map((wi, k) => {
                  const on = card.items.some(x => (x.name || "").trim() === (wi.name || "").trim());
                  return (
                    <button key={k} type="button" onClick={() => togglePick(wi)}
                      style={{display: "inline-flex", alignItems: "center", gap: 5, padding: "5px 12px", borderRadius: 999, cursor: "pointer", fontFamily: "inherit", fontSize: 12.5, fontWeight: 700,
                        border: `1.5px solid ${on ? t.color : "var(--line-strong)"}`,
                        background: on ? t.color : "var(--surface)", color: on ? "#fff" : "var(--ink-2)"}}>
                      {on ? "✓" : "＋"} {wi.name}{wi.qty ? <span style={{fontWeight: 400, fontSize: 11, opacity: 0.8}}>({wi.qty} {wi.unit || ""})</span> : null}
                    </button>
                  );
                })}
              </div>
            )}
            <div style={{display: "flex", flexDirection: "column", gap: 7}}>
              {card.items.map((it, k) => (
                <div key={it.id} style={{padding: 9, border: "1px solid var(--line)", borderLeft: `4px solid ${t.color}66`, borderRadius: 9, background: "var(--surface-2)"}}>
                  <div style={{display: "grid", gridTemplateColumns: "1fr 150px 74px 92px 30px", gap: 7, alignItems: "center"}}>
                    <WCItemNameInput value={it.name} placeholder={t.itemPh} woItems={woItems}
                      onChange={v => updItem(it.id, "name", v)}
                      onPickWo={wi => {
                        // เติมประวัติจากคลังชิ้นงานให้เอง (เฉพาะช่องที่ยังว่าง) — เหมือนกดชิปเลือกชิ้น
                        const lf = (window.SSSItemLib && window.SSSItemLib.fill && window.SSSItemLib.fill(wi.name, card.type)) || null;
                        onChange({ ...card,
                          detail: (card.detail || "").trim() ? card.detail : ((lf && lf.detail) || card.detail || ""),
                          items: card.items.map(x => x.id === it.id
                          ? { ...x, name: wi.name, qty: wi.qty != null ? wi.qty : x.qty, unit: wi.unit || x.unit,
                              material: x.material || (lf && lf.material) || "",
                              path: x.path || (lf && lf.path) || "",
                              spec: x.spec || (lf && lf.spec) || "",
                              photos: (x.photos && x.photos.length) ? x.photos : (lf ? lf.photos : []).slice(0, 6) }
                          : x) });
                        if (lf) { try { window.toast && window.toast(`📚 เติมประวัติ "${wi.name}" จากคลังให้แล้ว`); } catch (e) {} }
                      }}/>
                    <input className="input" value={it.material} onChange={e => updItem(it.id, "material", e.target.value)} placeholder="วัสดุ/หนา"/>
                    <input className="input" type="number" min="0" step="any" style={{textAlign: "center", fontWeight: 700}} value={it.qty} onChange={e => updItem(it.id, "qty", e.target.value)}/>
                    <window.UI.UnitSelect value={it.unit} onChange={v => updItem(it.id, "unit", v)}/>
                    <button className="icon-btn" title="ลบรายการ" onClick={() => delItem(it.id)}><I.trash size={12}/></button>
                  </div>
                  <div style={{display: "flex", gap: 7, flexWrap: "wrap", alignItems: "center", marginTop: 8}}>
                    {(it.photos || []).map((u, x) => (
                      <div key={x} style={{position: "relative"}}>
                        <img src={u} alt="" title="กดดูขนาดเต็ม" onClick={() => window.openPhotoZoom && window.openPhotoZoom(it.photos, x)}
                          style={{width: 84, height: 72, objectFit: "contain", borderRadius: 6, border: "1px solid var(--line-strong)", background: "#fff", cursor: "zoom-in", display: "block"}}/>
                        <button className="icon-btn" title="ลบรูปนี้" onClick={() => delPhoto(it.id, x)}
                          style={{position: "absolute", top: -6, right: -6, width: 19, height: 19, background: "var(--danger)", color: "#fff", borderRadius: "50%", padding: 0}}><I.close size={9}/></button>
                      </div>
                    ))}
                    <window.UI.DropZone>
                      <label title={`เพิ่ม${t.photoLabel} (ลากรูปมาวางได้)`} style={{width: 84, height: 72, borderRadius: 6, cursor: "pointer", border: "2px dashed var(--line-strong)", display: "grid", placeItems: "center", background: "var(--surface)"}}>
                        <input type="file" accept="image/*" multiple style={{display: "none"}} onChange={e => addPhotos(it.id, e)}/>
                        <span style={{display: "flex", flexDirection: "column", alignItems: "center", gap: 2, color: "var(--ink-3)"}}><I.camera size={18}/><span style={{fontSize: 10}}>{t.attach || "แนบรูป"}</span></span>
                      </label>
                    </window.UI.DropZone>
                    {!t.noPath && <input className="input" style={{flex: 1, minWidth: 190, fontSize: 12}} value={it.path} onChange={e => updItem(it.id, "path", e.target.value)}
                      placeholder={t.pathPh || "📁 PATH ที่เก็บไฟล์แบบ (ไม่บังคับ)"}/>}
                  </div>
                  {t.extra && (
                    <div style={{display: "flex", gap: 7, alignItems: "center", marginTop: 7, flexWrap: "wrap"}}>
                      <span style={{fontSize: 11.5, fontWeight: 800, color: t.color, flexShrink: 0}}>⚙️ {t.extra.label}:</span>
                      <input className="input" style={{flex: 1, minWidth: 170}} value={it.spec || ""} onChange={e => updItem(it.id, "spec", e.target.value)} placeholder={t.extra.ph}/>
                      {(t.extra.quick || []).map(q => (
                        <button key={q} type="button" className="btn sm" style={{borderColor: t.color, color: t.color, fontWeight: 700}}
                          onClick={() => updItem(it.id, "spec", ((it.spec || "").trim() ? it.spec.trim() + " · " : "") + q)}>{q}</button>
                      ))}
                    </div>
                  )}
                </div>
              ))}
            </div>
            {busy && <div style={{fontSize: 11.5, color: "var(--ink-3)", marginTop: 5}}>⏳ {busy}</div>}
            <Btn size="sm" icon={I.plus} onClick={addItem} style={{marginTop: 7, borderColor: t.color, color: t.color, fontWeight: 700}}>เพิ่มรายการ</Btn>
          </div>

          {/* งานส่งของ: วันนัดส่ง (ลิงค์ไปหน้าส่งของประจำวันอัตโนมัติ) */}
          {t.deliver ? (
            <div style={{border: "1px solid var(--line)", borderRadius: 9, padding: "9px 11px", background: "rgba(21,128,61,0.06)"}}>
              <div style={{fontSize: 12.5, fontWeight: 700, marginBottom: 7}}>🚚 นัดส่งของ <span style={{fontWeight: 400, fontSize: 11, color: "var(--ink-3)"}}>— บันทึกใบสั่งงานแล้ว รายการจะขึ้นหน้า "ส่งของประจำวัน" ให้เอง (ตรวจนับ+รูป+ลายเซ็นที่นั่น)</span></div>
              <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 7}}>
                <div className="field"><label>วันที่นัดส่ง</label><input className="input" type="date" value={card.date} onChange={e => upd("date", e.target.value)}/></div>
                <div className="field"><label>เวลานัด</label><input className="input mono" type="time" value={card.start} onChange={e => upd("start", e.target.value)}/></div>
              </div>
              <div className="field" style={{marginTop: 7}}><label>📍 สถานที่ / จุดส่ง</label>
                <input className="input" value={card.place || ""} onChange={e => upd("place", e.target.value)} placeholder="เช่น หน้างานลูกค้า ต.ท่าสองคอน · ร้าน Both Audio"/></div>
              <div style={{display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 7, marginTop: 7}}>
                <div className="field"><label>👤 ผู้รับปลายทาง</label>
                  <input className="input" value={card.receiver || ""} onChange={e => upd("receiver", e.target.value)} placeholder="ชื่อคนรับของ"/></div>
                <div className="field"><label>☎️ เบอร์ติดต่อ</label>
                  <input className="input mono" value={card.phone || ""} onChange={e => upd("phone", e.target.value)} placeholder="08x-xxx-xxxx"/></div>
              </div>
            </div>
          ) : (
          <div style={{border: "1px solid var(--line)", borderRadius: 9, padding: "9px 11px", background: "var(--surface-2)"}}>
            <label style={{display: "flex", alignItems: "center", gap: 8, cursor: "pointer", fontSize: 12.5, fontWeight: 700}}>
              <input type="checkbox" checked={!!card.machineId} onChange={e => {
                if (e.target.checked) onChange({ ...card, machineId: (machines[0] || {}).id || "", date: card.date || card.due || wcToday(), start: card.start || "09:00", end: card.end || "12:00" });
                else onChange({ ...card, machineId: "", date: "", start: "", end: "" });
              }}/>
              🏭 จองคิวเครื่องจักรสำหรับงานนี้
            </label>
            {!!card.machineId && (machines.length === 0
              ? <div style={{marginTop: 7, fontSize: 12, color: "var(--warning)"}}>⚠️ ยังไม่มีเครื่องจักรในระบบ — เพิ่มที่เมนู "คิวงานเครื่องจักร" ก่อน</div>
              : <div style={{display: "grid", gridTemplateColumns: "1.4fr 1fr 0.8fr 0.8fr", gap: 7, marginTop: 8}}>
                  <div className="field"><label>เครื่อง</label>
                    <select className="input" value={card.machineId} onChange={e => upd("machineId", e.target.value)}>
                      {machines.map(m => <option key={m.id} value={m.id}>{m.name || m.id}</option>)}
                    </select></div>
                  <div className="field"><label>วันที่</label><input className="input" type="date" value={card.date} onChange={e => upd("date", e.target.value)}/></div>
                  <div className="field"><label>เริ่ม</label><input className="input mono" type="time" value={card.start} onChange={e => upd("start", e.target.value)}/></div>
                  <div className="field"><label>เสร็จ</label><input className="input mono" type="time" value={card.end} onChange={e => upd("end", e.target.value)}/></div>
                </div>)}
          </div>
          )}
        </div>
      )}
      {pickEmp && (
        <WCEmpPick emps={emps} value={card.assigneeId} onClose={() => setPickEmp(false)}
          onPick={(e2) => { onChange({ ...card, assigneeId: e2 ? e2.id : "", assigneeName: e2 ? e2.name : "" }); setPickEmp(false); }}/>
      )}
      {pickHelper && (
        <WCEmpPick emps={emps.filter(e2 => e2.id !== card.assigneeId && !(card.helpers || []).some(h => h.id === e2.id))}
          value={""} onClose={() => setPickHelper(false)}
          onPick={(e2) => { if (e2) upd("helpers", [...(card.helpers || []), { id: e2.id, name: e2.name }]); setPickHelper(false); }}/>
      )}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// ส่วนจัดการการ์ดทั้งชุด (วางในฟอร์มใบสั่งงาน)
// ════════════════════════════════════════════════════════════════════════════
function WCCardsEditor({ cards, onChange, emps, machines, woItems }) {
  const { Btn } = window.UI;
  const [lastAdded, setLastAdded] = useStateWC(null);   // ใบที่เพิ่งเพิ่ม = ใบเดียวที่กางให้ (ที่เหลือย่อเป็นแถบสี)
  const add = (type) => {
    const t = wcType(type);
    let title = t.label;
    if (type === "custom") {
      const name = window.prompt("ตั้งชื่องานนี้ (เช่น งานเจาะรู, งานขัดเงา)");
      if (!name || !name.trim()) return;   // ยกเลิก = ไม่เพิ่ม
      title = name.trim();
    }
    const id = wcUid();
    onChange([...cards, wcNormalize({ id, type, title, status: "รอทำ",
      date: type === "deliver" ? wcToday() : "", start: type === "deliver" ? "10:00" : "",
      items: [{ id: wcUid(), name: "", material: "", path: "", qty: 1, unit: type === "deliver" ? "ชิ้น" : "ชุด", photos: [] }] })]);
    setLastAdded(id);
  };
  const move = (i, d) => {
    const j = i + d;
    if (j < 0 || j >= cards.length) return;
    const next = cards.slice();
    [next[i], next[j]] = [next[j], next[i]];
    onChange(next);
  };
  return (
    <div className="field">
      <label>🗂️ การ์ดงาน — 1 การ์ด = 1 งาน (เรียงตามลำดับที่จะทำ · กดแถบสีเพื่อกางแก้)</label>
      {/* ปุ่มเพิ่มการ์ดอยู่บนสุด — ไม่ต้องเลื่อนผ่านการ์ดทั้งหมด */}
      <div style={{display: "flex", gap: 7, flexWrap: "wrap", marginBottom: 9, alignItems: "center"}}>
        <span style={{fontSize: 12.5, color: "var(--ink-3)", fontWeight: 700}}>➕ เพิ่มการ์ด:</span>
        {WC_ORDER.map(k => (
          <button key={k} className="btn" onClick={() => add(k)}
            style={{borderColor: WC_TYPES[k].color, color: WC_TYPES[k].color, fontWeight: 700, fontSize: 13.5, padding: "7px 14px"}}>
            {WC_TYPES[k].emoji} {WC_TYPES[k].label}
          </button>
        ))}
      </div>
      {cards.length === 0 && (
        <div style={{padding: "14px 12px", textAlign: "center", border: "1.5px dashed var(--line-strong)", borderRadius: 10, background: "var(--surface-2)", fontSize: 12.5, color: "var(--ink-3)"}}>
          ยังไม่มีการ์ดงาน — กดปุ่มด้านบนเพื่อเพิ่มงานแรก (เช่น ✂️ งานตัด → 📐 งานพับ → 🎨 งานทำสี)
        </div>
      )}
      <div style={{display: "flex", flexDirection: "column", gap: 9}}>
        {cards.map((c, i) => (
          <WCCardEditor key={c.id} card={c} index={i} total={cards.length} emps={emps} machines={machines} woItems={woItems}
            defaultOpen={c.id === lastAdded}
            onChange={nc => onChange(cards.map((x, j) => j === i ? nc : x))}
            onRemove={() => onChange(cards.filter((_, j) => j !== i))}
            onMove={d => move(i, d)}/>
        ))}
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// แถบการ์ดในหน้าโปรเจกต์ — แถบสีเด่นบอกทันทีว่าใบนี้มีงานอะไรบ้าง เรียงลำดับไหน
// แบบย่อ: แถบสี + ชื่องาน + สรุปรายการ · กดแถบเพื่อกาง/ย่อรายละเอียด+รูป
// ════════════════════════════════════════════════════════════════════════════
function WCCardsList({ cards, onChange, woNo, woItems }) {
  const [openId, setOpenId] = useStateWC(null);
  const [editKey, setEditKey] = useStateWC(null);   // key ของการ์ดที่กำลังแก้ (id หรือ index)
  const [draft, setDraft] = useStateWC(null);       // สำเนาการ์ดระหว่างแก้ — กดบันทึกค่อยมีผลจริง
  if (!cards || !cards.length) return null;
  const machines = wcLS("sss-machines", []) || [];
  const mName = (id) => (machines.find(m => m.id === id) || {}).name || id;
  const emps = (window.SSSData && window.SSSData.Employees) || [];
  const keyOf = (c, i) => (c.id != null && c.id !== "" ? c.id : i);
  // แก้ไข/เปลี่ยนสถานะได้ตรงนี้เลย (เมื่อหน้าที่เรียกส่ง onChange มา) — ไม่ต้องเปิดฟอร์มแก้ทั้งใบ
  const canEdit = typeof onChange === "function";
  const commitAt = (i, next) => onChange(cards.map((x, j) => j === i ? next : x));
  const cycleStatus = (c, i) => {
    const next = WC_STATUS[(WC_STATUS.indexOf(c.status || "รอทำ") + 1) % WC_STATUS.length];
    commitAt(i, { ...c, status: next });
  };
  const startEdit = (c, i) => { setDraft(wcNormalize(JSON.parse(JSON.stringify(c)))); setEditKey(keyOf(c, i)); setOpenId(null); };
  const cancelEdit = () => { setEditKey(null); setDraft(null); };
  const saveEdit = (i) => { commitAt(i, draft); cancelEdit(); window.toast && window.toast("บันทึกการ์ดแล้ว ✓"); };
  const moveCard = (i, d) => {
    const j = i + d;
    if (j < 0 || j >= cards.length) return;
    const next = cards.slice();
    [next[i], next[j]] = [next[j], next[i]];
    onChange(next);
  };
  return (
    <div style={{display: "flex", flexDirection: "column", gap: 6, marginTop: 10}}>
      {cards.map((c, i) => {
        const t = wcType(c.type);
        const items = (c.items || []).filter(x => x.name);
        const photos = (c.items || []).flatMap(x => x.photos || []);
        const done = c.status === "เสร็จแล้ว";
        const open = openId === (c.id || i);
        if (canEdit && editKey === keyOf(c, i) && draft) {
          return (
            <div key={c.id || i} style={{borderRadius: 9, border: `2px solid ${t.color}`, padding: 6, background: "var(--surface-2)"}}>
              <WCCardEditor card={draft} index={i} total={cards.length} emps={emps} machines={machines} woItems={woItems} defaultOpen
                onChange={setDraft}
                onRemove={async () => {
                  const ok = window.confirmDelete
                    ? await window.confirmDelete(`การ์ด ${draft.title || t.label}`, `${(draft.items || []).filter(x => x.name).length} รายการ`)
                    : window.confirm("ลบการ์ดนี้?");
                  if (!ok) return;
                  onChange(cards.filter((_, j) => j !== i));
                  cancelEdit();
                }}
                onMove={d => moveCard(i, d)}/>
              <div style={{display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 8}}>
                <button className="btn sm" onClick={cancelEdit}>ยกเลิก</button>
                <button className="btn sm" onClick={() => saveEdit(i)}
                  style={{background: t.color, borderColor: t.color, color: "#fff", fontWeight: 700}}>💾 บันทึกการ์ดนี้</button>
              </div>
            </div>
          );
        }
        return (
          <div key={c.id || i} style={{borderRadius: 9, overflow: "hidden", border: `1px solid ${t.color}44`}}>
            {/* แถบสีหลัก — ตามแบบที่ผู้ใช้ร่างมา: แถบทึบสีประจำประเภทงาน มองปราดเดียวรู้ */}
            <div onClick={() => setOpenId(open ? null : (c.id || i))} title="กดเพื่อดู/ซ่อนรายละเอียด"
              style={{display: "flex", alignItems: "center", gap: 9, padding: "8px 12px", cursor: "pointer",
                background: done ? `linear-gradient(90deg, ${t.color}55, ${t.color}33)` : `linear-gradient(90deg, ${t.color}, ${t.color}cc)`,
                color: "#fff"}}>
              <span style={{width: 22, height: 22, borderRadius: "50%", background: "rgba(255,255,255,0.25)", display: "grid", placeItems: "center", fontSize: 11.5, fontWeight: 800, flexShrink: 0}}>{i + 1}</span>
              <span style={{fontSize: 15}}>{t.emoji}</span>
              <b style={{fontSize: 13, textShadow: "0 1px 2px rgba(0,0,0,0.25)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{c.title || t.label}</b>
              <span style={{fontSize: 11, opacity: 0.9, flexShrink: 0}}>
                {items.length > 0 && `${items.length} รายการ`}
                {photos.length > 0 && ` · ${photos.length} รูป`}
              </span>
              <span style={{marginLeft: "auto", display: "flex", alignItems: "center", gap: 7, flexShrink: 0}}>
                {c.machineId && c.date && <span style={{fontSize: 10.5, background: "rgba(0,0,0,0.25)", padding: "2px 8px", borderRadius: 99}}>🏭 {wcThai(c.date)}{c.start ? ` ${c.start}` : ""}</span>}
                <span title={canEdit ? "กดเพื่อเปลี่ยนสถานะ: รอทำ → กำลังทำ → เสร็จแล้ว" : undefined}
                  onClick={canEdit ? (e => { e.stopPropagation(); cycleStatus(c, i); }) : undefined}
                  style={{fontSize: 10.5, background: done ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,0.22)", color: done ? t.color : "#fff", padding: "2px 9px", borderRadius: 99, fontWeight: 700,
                    cursor: canEdit ? "pointer" : undefined, border: canEdit ? "1px dashed rgba(255,255,255,0.55)" : "none"}}>
                  {done ? "✓ เสร็จแล้ว" : (c.status || "รอทำ")}
                </span>
                {canEdit && (
                  <button title="แก้ไขการ์ดนี้ (รายการ/รูปแบบ/คิวเครื่อง/สถานะ)" onClick={e => { e.stopPropagation(); startEdit(c, i); }}
                    style={{width: 24, height: 24, borderRadius: 6, border: "1px solid rgba(255,255,255,0.5)", background: "rgba(255,255,255,0.18)", color: "#fff", cursor: "pointer", display: "grid", placeItems: "center", padding: 0}}>
                    <I.edit size={12}/>
                  </button>
                )}
                <span style={{fontSize: 10, opacity: 0.85}}>{open ? "▲" : "▼"}</span>
              </span>
            </div>
            {/* รายละเอียดแบบกาง */}
            {open && (
              <div style={{padding: "9px 12px", background: "var(--surface)", fontSize: 12.5}}>
                {items.length > 0 && (
                  <div style={{display: "flex", flexDirection: "column", gap: 3, marginBottom: c.detail || photos.length ? 7 : 0}}>
                    {items.map((x, k) => (
                      <div key={k} style={{display: "flex", gap: 7, alignItems: "baseline"}}>
                        <span style={{color: "var(--ink-4)", fontSize: 11, flexShrink: 0}}>{k + 1}.</span>
                        <span style={{fontWeight: 600}}>{x.name}</span>
                        {x.spec ? <span style={{fontSize: 11, fontWeight: 700, color: t.color}}>⚙️ {x.spec}</span> : null}
                        <span style={{color: "var(--ink-3)", fontSize: 11.5}}>{x.material || ""}</span>
                        <span style={{marginLeft: "auto", fontWeight: 700, flexShrink: 0}}>{x.qty || 1} <span style={{fontWeight: 400, fontSize: 10.5, color: "var(--ink-3)"}}>{x.unit || "ชุด"}</span></span>
                      </div>
                    ))}
                  </div>
                )}
                {c.detail && <div style={{color: "var(--ink-2)", whiteSpace: "pre-wrap", lineHeight: 1.55, marginBottom: photos.length ? 7 : 0}}>📝 {c.detail}</div>}
                {c.machineId && c.date && (
                  <div style={{fontSize: 11.5, color: "var(--info)", fontWeight: 600, marginBottom: photos.length ? 7 : 0}}>
                    🏭 คิวเครื่องจักร: {mName(c.machineId)} · {wcThai(c.date)}{c.start ? ` ${c.start}${c.end ? "–" + c.end : ""}` : ""}
                  </div>
                )}
                {c.type === "deliver" && (() => {
                  const dd = woNo ? ((window.SSSData || {}).DailyDeliveries || []).find(d => d && d.id === "WODD-" + woNo + "-" + c.id) : null;
                  return (
                    <div style={{fontSize: 11.5, fontWeight: 600, color: "var(--ink-2)", marginBottom: photos.length ? 7 : 0, display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center"}}>
                      {c.date && <span>🚚 นัดส่ง {wcThai(c.date)}{c.start ? ` ${c.start}` : ""}</span>}
                      {c.place && <span>📍 {c.place}</span>}
                      {c.receiver && <span>👤 {c.receiver}{c.phone ? ` ☎️ ${c.phone}` : ""}</span>}
                      {dd && <span style={{padding: "1px 9px", borderRadius: 99, fontSize: 10.5, fontWeight: 700,
                        background: dd.status === "ส่งแล้ว" ? "var(--success-bg, #dcfce7)" : "var(--surface-2)",
                        color: dd.status === "ส่งแล้ว" ? "var(--success)" : "var(--ink-2)",
                        border: "1px solid " + (dd.status === "ส่งแล้ว" ? "var(--success)" : "var(--line-strong)")}}>
                        {dd.status === "ส่งแล้ว" ? "✓ ส่งแล้ว" : "⏳ " + (dd.status || "รอจัดส่ง")} · {dd.no}</span>}
                    </div>
                  );
                })()}
                {photos.length > 0 && (
                  <div style={{display: "flex", gap: 6, flexWrap: "wrap"}}>
                    {photos.slice(0, 8).map((u, k) => (
                      <img key={k} src={u} alt="" title="กดดูขนาดเต็ม" onClick={() => window.openPhotoZoom && window.openPhotoZoom(photos, k)}
                        style={{width: 74, height: 62, objectFit: "contain", borderRadius: 6, border: "1px solid var(--line)", background: "#fff", cursor: "zoom-in"}}/>
                    ))}
                    {photos.length > 8 && (
                      <span onClick={() => window.openPhotoZoom && window.openPhotoZoom(photos, 8)}
                        style={{width: 74, height: 62, borderRadius: 6, border: "1px dashed var(--line-strong)", display: "grid", placeItems: "center", fontSize: 12, color: "var(--ink-3)", cursor: "pointer"}}>+{photos.length - 8}</span>
                    )}
                  </div>
                )}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ── HTML สำหรับใบสั่งงานที่พิมพ์ออกกระดาษ ──
// sepIdx (ไม่บังคับ) = Set ของ index การ์ดที่ถูกพิมพ์เป็น "ชุดใบงานแยก" — ป้ายจะชี้ไปดูชุดนั้นแทน
function wcPrintHTML(cards, accent, sepIdx) {
  if (!cards || !cards.length) return "";
  const esc = (s) => String(s == null ? "" : s).replace(/</g, "&lt;");
  const machines = wcLS("sss-machines", []) || [];
  const mName = (id) => esc((machines.find(m => m.id === id) || {}).name || id);
  const rows = cards.map((c, i) => {
    const t = wcType(c.type);
    const items = (c.items || []).filter(x => x.name || (x.photos || []).length);   // มีแบบแต่ยังไม่ตั้งชื่อ ก็ต้องขึ้นตาราง
    const nP = (c.items || []).reduce((s, x) => s + ((x.photos || []).length), 0);
    return `
      <div style="page-break-inside:avoid;break-inside:avoid;border:1.5px solid #d6d3d1;border-left:5px solid ${t.color};border-radius:8px;padding:8px 11px;margin-bottom:9px">
        <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:6px">
          <span style="width:22px;height:22px;border-radius:50%;background:${t.color};color:#fff;display:inline-grid;place-items:center;font-size:11.5px;font-weight:800">${i + 1}</span>
          <span style="display:inline-flex;align-items:center;gap:7px;padding:3px 14px;border:2px solid ${t.color};background:${t.color}12;border-radius:9px;font-size:16px;font-weight:800;color:${t.color}">${t.emoji} ${esc(c.title || t.label)}</span>
          <span style="font-size:10px;color:#78716c">${esc(t.label)}</span>
          ${c.machineId && c.date ? `<span style="margin-left:auto;font-size:10.5px;color:#1d4ed8">🏭 ${mName(c.machineId)} · ${esc(wcThai(c.date))} ${esc(c.start || "")}${c.end ? "–" + esc(c.end) : ""}</span>` : ""}
          ${nP ? `<span style="${c.machineId && c.date ? "" : "margin-left:auto;"}font-size:10px;font-weight:700;color:#57534e;background:#f5f5f4;border:1px solid #e7e5e4;border-radius:99px;padding:1px 8px">📎 แบบ/รูป ${nP} รูป — ${(sepIdx && sepIdx.has(i)) ? "ดูใบงานชุดแยกของงานนี้" : "พิมพ์ขนาดใหญ่หน้าท้ายเอกสาร"}</span>` : ""}
        </div>
        ${items.length ? `<table style="width:100%;border-collapse:collapse;font-size:11px">
          <tr style="background:#f7f6f4"><th style="border:1px solid #e7e5e4;padding:3px 7px;text-align:left;width:8mm">#</th>
          <th style="border:1px solid #e7e5e4;padding:3px 7px;text-align:left">รายการ</th>
          <th style="border:1px solid #e7e5e4;padding:3px 7px;text-align:left;width:30mm">วัสดุ</th>
          <th style="border:1px solid #e7e5e4;padding:3px 7px;text-align:right;width:22mm">จำนวน</th>
          <th style="border:1px solid #e7e5e4;padding:3px 7px;width:14mm">ทำแล้ว</th></tr>
          ${items.map((x, k) => `<tr>
            <td style="border:1px solid #e7e5e4;padding:3px 7px;text-align:center;color:#78716c">${k + 1}</td>
            <td style="border:1px solid #e7e5e4;padding:3px 7px;font-weight:600">${esc(x.name || "(ดูแบบ)")}${x.spec ? `<div style="font-size:9px;font-weight:700;color:${t.color}">⚙️ ${esc(x.spec)}</div>` : ""}${x.path ? `<div style="font-size:8.5px;font-weight:400;color:#78716c">📁 ${esc(x.path)}</div>` : ""}</td>
            <td style="border:1px solid #e7e5e4;padding:3px 7px">${esc(x.material || "—")}</td>
            <td style="border:1px solid #e7e5e4;padding:3px 7px;text-align:right;font-weight:700">${esc(x.qty || 1)} <span style="font-weight:400;font-size:9px;color:#57534e">${esc(x.unit || "ชุด")}</span></td>
            <td style="border:1px solid #e7e5e4;padding:3px 7px;text-align:center"><span style="display:inline-block;width:3.5mm;height:3.5mm;border:0.5pt solid #57534e;border-radius:1mm"></span></td>
          </tr>`).join("")}
        </table>` : ""}
        ${c.detail ? `<div style="font-size:11px;margin-top:5px;white-space:pre-wrap;color:#1c1917">📝 <b>วิธีทำ:</b> ${esc(c.detail)}</div>` : ""}
      </div>`;
  }).join("");
  return `<div style="margin-bottom:10px">
    <div style="font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:#44403c;margin-bottom:5px">🗂️ ลำดับงานที่ต้องทำ (${cards.length} งาน)</div>
    ${rows}
  </div>`;
}

window.WOCards = {
  TYPES: WC_TYPES, ORDER: WC_ORDER, STATUS: WC_STATUS,
  type: wcType, uid: wcUid, normalize: wcNormalize, fromCutOrder: wcFromCutOrder,
  syncQueue: wcSyncQueue, removeQueue: wcRemoveQueue, syncDeliveries: wcSyncDeliveries, removeDeliveries: wcRemoveDeliveries, printHTML: wcPrintHTML,
  Editor: WCCardsEditor, List: WCCardsList,
};
window.WOCardsEditor = WCCardsEditor;
window.WOCardsList = WCCardsList;
