/* global React, I, UI, SSSData */
const { useState: useStateP3, useMemo: useMemoP3 } = React;

const STATUS_COLORS = {
  "ส่งงาน": "#15803d",
  "รอเก็บเงิน": "#0d9488",
  "กำลังผลิต": "#1d4ed8",
  "ตรวจสอบคุณภาพ": "#7c3aed",
  "ออกแบบ 3D": "#c2410c",
  "ร่าง": "#78716c"
};

const UPDATE_ICONS = {
  milestone: "🏁",
  progress: "▸",
  issue: "⚠",
  complete: "✓",
  purchase: "📦",
  cost: "💰"
};

// =============== Helpers ===============
function parseISO(s) { const [y, m, d] = s.split("-").map(Number); return new Date(y, m - 1, d); }
function fmtThaiDate(s) {
  const months = ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."];
  const d = parseISO(s);
  return `${d.getDate()} ${months[d.getMonth()]} ${d.getFullYear() + 543}`;
}
function daysBetween_d(a, b) { return Math.round((b - a) / 86400000); }

// =============== Gantt chart ===============
function GanttChart({ projects, onSelect, today }) {
  // Determine date range
  const allDates = projects.flatMap(p => [parseISO(p.start), parseISO(p.end)]);
  const min = new Date(Math.min(...allDates));
  const max = new Date(Math.max(...allDates));
  // Round to month boundaries
  min.setDate(1);
  max.setMonth(max.getMonth() + 1);
  max.setDate(0);
  const totalDays = daysBetween_d(min, max) + 1;

  // Build month columns
  const months = [];
  let cursor = new Date(min);
  while (cursor <= max) {
    const monthStart = new Date(cursor);
    const monthEnd = new Date(cursor.getFullYear(), cursor.getMonth() + 1, 0);
    const days = (monthEnd - monthStart) / 86400000 + 1;
    months.push({
      label: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค."][monthStart.getMonth()],
      year: monthStart.getFullYear() + 543,
      days,
      startDay: daysBetween_d(min, monthStart)
    });
    cursor.setMonth(cursor.getMonth() + 1);
  }

  const todayDate = today || new Date(2026, 4, 22);
  const todayOffset = daysBetween_d(min, todayDate);

  return (
    <div style={{display: "grid", gridTemplateColumns: "320px 1fr", border: "1px solid var(--line)", borderRadius: 8, overflow: "hidden", background: "var(--surface)"}}>
      {/* Header */}
      <div style={{borderRight: "1px solid var(--line)", borderBottom: "1px solid var(--line)", padding: "10px 12px", fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--ink-3)", background: "var(--surface-2)", display: "flex", alignItems: "center"}}>โปรเจกต์</div>
      <div style={{borderBottom: "1px solid var(--line)", background: "var(--surface-2)", position: "relative", overflow: "hidden"}}>
        <div style={{display: "flex", height: "100%"}}>
          {months.map((m, i) => (
            <div key={i} style={{
              flexGrow: m.days,
              flexBasis: 0,
              borderLeft: i === 0 ? "0" : "1px solid var(--line)",
              padding: "10px 8px",
              fontSize: 11,
              fontWeight: 600,
              color: "var(--ink-2)",
              display: "flex",
              flexDirection: "column"
            }}>
              <span>{m.label} <span style={{color: "var(--ink-4)", fontWeight: 400}}>{m.year}</span></span>
            </div>
          ))}
        </div>
      </div>

      {/* Body rows */}
      {projects.map((p, idx) => {
        const startOff = Math.max(0, daysBetween_d(min, parseISO(p.start)));
        const dur = daysBetween_d(parseISO(p.start), parseISO(p.end)) + 1;
        const left = (startOff / totalDays) * 100;
        const width = (dur / totalDays) * 100;
        const color = STATUS_COLORS[p.status] || "#78716c";
        return (
          <React.Fragment key={p.code}>
            <div style={{borderRight: "1px solid var(--line)", borderBottom: idx < projects.length-1 ? "1px solid var(--line-soft)" : 0, padding: "10px 12px", cursor: "pointer", display: "flex", alignItems: "center", gap: 8}} onClick={() => onSelect(p)}>
              <div style={{flex: 1, minWidth: 0}}>
                <div className="mono" style={{fontSize: 10.5, color: "var(--ink-3)"}}>{p.code}</div>
                <div style={{fontWeight: 500, fontSize: 12.5, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginTop: 2}}>{p.name}</div>
                <div style={{fontSize: 10.5, color: "var(--ink-3)", marginTop: 1}}>{p.customer} · {p.lead}</div>
              </div>
            </div>
            <div style={{borderBottom: idx < projects.length-1 ? "1px solid var(--line-soft)" : 0, position: "relative", height: 56, padding: "8px 0"}}>
              {/* Month grid lines */}
              <div style={{position: "absolute", inset: 0, display: "flex", pointerEvents: "none"}}>
                {months.map((m, i) => (
                  <div key={i} style={{flexGrow: m.days, flexBasis: 0, borderLeft: i === 0 ? "0" : "1px dashed var(--line)"}}/>
                ))}
              </div>
              {/* Today line */}
              {todayOffset >= 0 && todayOffset <= totalDays && (
                <div style={{position: "absolute", top: 0, bottom: 0, left: `${(todayOffset/totalDays)*100}%`, borderLeft: "1.5px dashed var(--danger)", zIndex: 1}}>
                  <div style={{position: "absolute", top: -6, left: -22, fontSize: 9, color: "var(--danger)", fontWeight: 600, background: "var(--surface)", padding: "0 4px"}}>วันนี้</div>
                </div>
              )}
              {/* Bar */}
              <div onClick={() => onSelect(p)} style={{
                position: "absolute",
                left: `${left}%`,
                width: `${width}%`,
                top: 10,
                bottom: 10,
                background: color + "26",
                border: `1.5px solid ${color}`,
                borderRadius: 5,
                cursor: "pointer",
                overflow: "hidden",
                display: "flex",
                alignItems: "center",
                padding: "0 8px",
                gap: 6
              }}>
                {/* Progress fill */}
                <div style={{position: "absolute", left: 0, top: 0, bottom: 0, width: `${p.progress}%`, background: color, opacity: 0.55}}/>
                <span style={{position: "relative", zIndex: 1, fontSize: 10.5, color, fontWeight: 600, whiteSpace: "nowrap"}}>{p.progress}%</span>
                <span style={{position: "relative", zIndex: 1, fontSize: 10.5, color: "var(--ink-1)", fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{p.status}</span>
              </div>
            </div>
          </React.Fragment>
        );
      })}
    </div>
  );
}

// =============== Month calendar (redesigned) ===============
function MonthCalendar({ projects, onSelect, monthDate, onChangeMonth }) {
  const year = monthDate.getFullYear();
  const m = monthDate.getMonth();
  const firstDay = new Date(year, m, 1);
  const lastDay = new Date(year, m + 1, 0);
  const calStart = new Date(firstDay);
  calStart.setDate(firstDay.getDate() - firstDay.getDay());
  const calEnd = new Date(lastDay);
  calEnd.setDate(lastDay.getDate() + (6 - lastDay.getDay()));
  const weeks = Math.round((calEnd - calStart) / 86400000 / 7) + 1;
  const todayDate = new Date(2026, 4, 22);

  const sorted = [...projects].sort((a, b) => parseISO(a.start) - parseISO(b.start));
  const visible = sorted.filter(p => {
    const ps = parseISO(p.start), pe = parseISO(p.end);
    return pe >= calStart && ps <= calEnd;
  });

  // Per-week segments with compact lane packing (no empty lanes)
  const weekData = [];
  for (let w = 0; w < weeks; w++) {
    const ws = new Date(calStart); ws.setDate(calStart.getDate() + w * 7);
    const we = new Date(ws); we.setDate(ws.getDate() + 6);
    const segs = [];
    visible.forEach(p => {
      const ps = parseISO(p.start), pe = parseISO(p.end);
      if (pe < ws || ps > we) return;
      const segStart = ps < ws ? ws : ps;
      const segEnd = pe > we ? we : pe;
      segs.push({
        project: p,
        colStart: segStart.getDay(),
        colSpan: segEnd.getDay() - segStart.getDay() + 1,
        startsHere: ps.getTime() === segStart.getTime(),
        endsHere: pe.getTime() === segEnd.getTime()
      });
    });
    segs.sort((a, b) => a.colStart - b.colStart || b.colSpan - a.colSpan);
    const laneEnd = [];
    segs.forEach(s => {
      let lane = laneEnd.findIndex(end => end < s.colStart);
      if (lane === -1) { lane = laneEnd.length; laneEnd.push(0); }
      laneEnd[lane] = s.colStart + s.colSpan - 1;
      s.lane = lane;
    });
    weekData.push({ segs, lanes: laneEnd.length });
  }

  const monthNames = ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม"];
  const headH = 32, barH = 24, barGap = 4;

  return (
    <div>
      {/* Toolbar */}
      <div style={{display: "flex", alignItems: "center", gap: 10, marginBottom: 14}}>
        <div style={{display: "flex", alignItems: "center", gap: 2, border: "1px solid var(--line)", borderRadius: 8, padding: 2, background: "var(--surface)"}}>
          <button className="icon-btn" onClick={() => onChangeMonth(-1)}><I.chevronLeft size={14}/></button>
          <button className="icon-btn" onClick={() => onChangeMonth(1)}><I.chevronRight size={14}/></button>
        </div>
        <div style={{fontSize: 17, fontWeight: 700, letterSpacing: "-0.01em"}}>{monthNames[m]} <span style={{color: "var(--ink-3)", fontWeight: 500}}>{year + 543}</span></div>
        <span className="spacer"/>
        <span style={{fontSize: 11.5, color: "var(--ink-3)"}}>{visible.length} โปรเจกต์ในเดือนนี้</span>
        <button className="btn sm" onClick={() => onChangeMonth("today")}>วันนี้</button>
      </div>

      <div style={{border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden", background: "var(--surface)", boxShadow: "var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.04))"}}>
        {/* Weekday header */}
        <div style={{display: "grid", gridTemplateColumns: "repeat(7, 1fr)", background: "var(--surface-2)", borderBottom: "1px solid var(--line)"}}>
          {["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสฯ","ศุกร์","เสาร์"].map((d, i) => (
            <div key={d} style={{padding: "9px 12px", fontSize: 11, fontWeight: 700, color: (i === 0 || i === 6) ? "var(--ink-4)" : "var(--ink-3)", letterSpacing: "0.04em", borderLeft: i === 0 ? 0 : "1px solid var(--line-soft)", textAlign: "center"}}>{d}</div>
          ))}
        </div>

        {/* Week rows */}
        {weekData.map((wd, w) => {
          const rowH = Math.max(86, headH + wd.lanes * (barH + barGap) + 10);
          return (
            <div key={w} style={{position: "relative", borderBottom: w < weeks - 1 ? "1px solid var(--line)" : 0, height: rowH}}>
              {/* Day cells */}
              <div style={{display: "grid", gridTemplateColumns: "repeat(7, 1fr)", position: "absolute", inset: 0}}>
                {[...Array(7)].map((_, d) => {
                  const dayDate = new Date(calStart);
                  dayDate.setDate(calStart.getDate() + w * 7 + d);
                  const inMonth = dayDate.getMonth() === m;
                  const isToday = dayDate.toDateString() === todayDate.toDateString();
                  const weekend = d === 0 || d === 6;
                  return (
                    <div key={d} style={{
                      borderLeft: d === 0 ? 0 : "1px solid var(--line-soft)",
                      background: !inMonth ? "var(--surface-2)" : isToday ? "var(--info-bg)" : weekend ? "color-mix(in oklab, var(--surface-2) 55%, transparent)" : "transparent",
                      padding: "6px 8px",
                      display: "flex",
                      justifyContent: "flex-end",
                      alignItems: "flex-start"
                    }}>
                      <div style={{
                        minWidth: 24, height: 24,
                        borderRadius: 99,
                        background: isToday ? "var(--accent)" : "transparent",
                        color: isToday ? "var(--accent-ink, white)" : !inMonth ? "var(--ink-4)" : "var(--ink-2)",
                        display: "grid", placeItems: "center",
                        fontWeight: isToday ? 700 : 500,
                        fontSize: 12,
                        fontVariantNumeric: "tabular-nums",
                        padding: "0 4px"
                      }}>{dayDate.getDate()}</div>
                    </div>
                  );
                })}
              </div>

              {/* Bars */}
              <div style={{
                position: "absolute",
                top: headH,
                left: 4, right: 4,
                display: "grid",
                gridTemplateColumns: "repeat(7, 1fr)",
                gridAutoRows: `${barH}px`,
                rowGap: barGap,
                columnGap: 2,
                pointerEvents: "none"
              }}>
                {wd.segs.map((s, i) => {
                  const color = STATUS_COLORS[s.project.status] || "#78716c";
                  return (
                    <div
                      key={s.project.code + i}
                      onClick={() => onSelect(s.project)}
                      style={{
                        gridRowStart: s.lane + 1,
                        gridColumnStart: s.colStart + 1,
                        gridColumnEnd: s.colStart + 1 + s.colSpan,
                        background: color,
                        color: "white",
                        borderRadius: s.startsHere && s.endsHere ? 7 : s.startsHere ? "7px 2px 2px 7px" : s.endsHere ? "2px 7px 7px 2px" : 2,
                        padding: s.startsHere ? "0 8px 0 5px" : "0 8px",
                        fontSize: 11,
                        fontWeight: 500,
                        cursor: "pointer",
                        pointerEvents: "all",
                        overflow: "hidden",
                        display: "flex",
                        alignItems: "center",
                        gap: 6,
                        boxShadow: "0 1px 2px rgba(0,0,0,0.12)"
                      }}
                      title={`${s.project.code} · ${s.project.name}\n${fmtThaiDate(s.project.start)} → ${fmtThaiDate(s.project.end)}\nสถานะ: ${s.project.status} (${s.project.progress}%)`}
                    >
                      {s.startsHere ? (
                        <span style={{fontSize: 9, fontWeight: 700, background: "rgba(255,255,255,0.25)", padding: "1.5px 6px", borderRadius: 99, flexShrink: 0, letterSpacing: "0.03em"}}>#{s.project.code.split("-").pop()}</span>
                      ) : (
                        <span style={{fontSize: 9, opacity: 0.7, flexShrink: 0}}>‹</span>
                      )}
                      <span style={{overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1}}>{s.project.name}</span>
                      {s.endsHere && (
                        <span style={{marginLeft: "auto", fontSize: 9.5, fontWeight: 700, background: "rgba(255,255,255,0.25)", padding: "1.5px 6px", borderRadius: 99, flexShrink: 0}}>{s.project.progress}%</span>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>

      {/* Project key */}
      {visible.length > 0 && (
        <div style={{marginTop: 12, display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(230px, 1fr))", gap: 6}}>
          {visible.map(p => {
            const color = STATUS_COLORS[p.status] || "#78716c";
            return (
              <div key={p.code} onClick={() => onSelect(p)} style={{
                display: "flex", alignItems: "center", gap: 8,
                padding: "7px 10px",
                background: "var(--surface)",
                border: "1px solid var(--line)",
                borderRadius: 7,
                cursor: "pointer",
                fontSize: 12
              }}>
                <span style={{width: 10, height: 10, borderRadius: 3, background: color, flexShrink: 0}}></span>
                <span className="mono" style={{fontSize: 10.5, color: "var(--ink-3)", flexShrink: 0}}>#{p.code.split("-").pop()}</span>
                <span style={{flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{p.name}</span>
                <span style={{fontSize: 10.5, color, fontWeight: 700, flexShrink: 0}}>{p.progress}%</span>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// =============== Project detail drawer ===============
function ProjectDetailDrawer({ project, onClose, onChanged }) {
  const D = window.SSSData;
  const PX = window.ProjX;
  const { Btn, Badge, Card, Drawer, fmt0 } = window.UI;
  const [updateText, setUpdateText] = useStateP3("");
  const [extra] = useStateP3(() => PX.pxGet(project.code));
  const [userUpdates, setUserUpdates] = useStateP3(extra.updates || []);
  const [photos, setPhotos] = useStateP3([]);
  const [showCam, setShowCam] = useStateP3(false);
  const [galleryCam, setGalleryCam] = useStateP3(false);
  const [gallery, setGallery] = useStateP3(extra.gallery || []);
  const [workOrders, setWorkOrders] = useStateP3(extra.workOrders || []);
  const [extraExpenses, setExtraExpenses] = useStateP3(extra.expenses || []);
  const [showWO, setShowWO] = useStateP3(false);
  const [showEdit, setShowEdit] = useStateP3(false);
  const [showExp, setShowExp] = useStateP3(false);
  const [evalFor, setEvalFor] = useStateP3(null);
  const [evals, setEvals] = useStateP3(() => window.WorkEvalStore ? window.WorkEvalStore.byProject(project.code) : []);
  const [progress, setProgress] = useStateP3(project.progress);
  const [statusVal, setStatusVal] = useStateP3(project.status);

  const updates = [...userUpdates, ...(project.updates || [])];
  const linkedExtra = (window.ProjX.pxGet(project.code).linkedExpenses) || [];
  const expenses = D.Expenses.filter(e => (project.expenseLinks || []).includes(e.no) || linkedExtra.includes(e.no));
  const totalExpense = expenses.reduce((s, e) => s + e.amount, 0) + extraExpenses.reduce((s, e) => s + (+e.amount || 0), 0);
  const left = project.budget - project.actual;
  const overBudget = project.actual > project.budget;
  const color = STATUS_COLORS[project.status] || "#78716c";

  const days = daysBetween_d(parseISO(project.start), parseISO(project.end)) + 1;
  const elapsed = Math.max(0, daysBetween_d(parseISO(project.start), new Date(2026, 4, 22)));
  const remaining = days - elapsed;

  const addUpdate = () => {
    const changed = updateText.trim() || photos.length > 0 || progress !== project.progress || statusVal !== project.status;
    if (!changed) { window.toast && window.toast("ยังไม่มีอะไรเปลี่ยนแปลง"); return; }
    if (photos.length === 0) {
      window.toast && window.toast("📷 ต้องถ่ายรูป/แนบรูปหน้างานอย่างน้อย 1 รูป ก่อนบันทึกอัปเดต");
      return;
    }
    const progressNote = progress !== project.progress ? ` · อัปเดต ${project.progress}% → ${progress}%` : "";
    const statusNote = statusVal !== project.status ? ` · เปลี่ยนสถานะ "${project.status}" → "${statusVal}"` : "";
    const text = (updateText.trim() || "อัปเดตความคืบหน้า") + progressNote + statusNote;
    const u = {
      date: PX.pxTodayISO(), who: "ปิยะ ศ.", text,
      type: progress === 100 ? "complete" : statusVal !== project.status ? "milestone" : "progress",
      photos: [...photos], progressFrom: project.progress, progressTo: progress
    };
    const nextUser = [u, ...userUpdates];
    setUserUpdates(nextUser);
    PX.pxSet(project.code, { updates: nextUser, progress, status: statusVal });
    project.progress = progress;
    project.status = statusVal;
    setUpdateText("");
    setPhotos([]);
    onChanged && onChanged();
    window.logActivity && window.logActivity("อัปเดตโปรเจกต์", `${project.code} → ${progress}% (แนบ ${u.photos.length} รูป)`, "update");
    window.toast && window.toast("บันทึกอัปเดตพร้อมรูป " + u.photos.length + " รูปแล้ว");
  };

  const resize = (f, max) => window.DeliveryStore && window.DeliveryStore.resizeImage
    ? window.DeliveryStore.resizeImage(f, max)
    : new Promise(res => { const r = new FileReader(); r.onload = () => res(r.result); r.readAsDataURL(f); });

  const onPickFile = async (e) => {
    const files = [...e.target.files].slice(0, 6);
    e.target.value = "";
    const loaded = [];
    for (const f of files) {
      const url = await resize(f, 700);
      if (url) loaded.push({ name: f.name, url });
    }
    setPhotos(p => [...p, ...loaded].slice(0, 6));
  };

  const saveGallery = (g) => { setGallery(g); PX.pxSet(project.code, { gallery: g }); };
  const onPickGallery = async (e) => {
    const files = [...e.target.files].slice(0, 12);
    e.target.value = "";
    const loaded = [];
    for (const f of files) {
      const url = await resize(f, 800);
      if (url) loaded.push({ name: f.name, url, date: PX.pxToday() });
    }
    saveGallery([...gallery, ...loaded]);
    if (loaded.length) window.toast && window.toast(`เพิ่ม ${loaded.length} รูปเข้าโปรเจกต์แล้ว`);
  };

  return (
    <Drawer open={true} onClose={onClose} title={`${project.code} · ${project.name}`} wide
      footer={<>
        <Btn icon={I.edit} onClick={() => setShowEdit(true)}>แก้ไขโปรเจกต์</Btn>
        <Btn icon={I.doc} onClick={() => setShowWO(true)}>ออกใบสั่งงาน</Btn>
        <Btn kind="primary" icon={I.print} onClick={() => PX.printJobSummaryDoc(project)}>สรุปงาน</Btn>
      </>}>
      {/* Hero */}
      <div style={{padding: 14, background: color + "10", border: `1px solid ${color}50`, borderRadius: 8, marginBottom: 14}}>
        <div style={{display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12, marginBottom: 10}}>
          <div>
            <div className="mono" style={{fontSize: 11, color: "var(--ink-3)"}}>{project.code}</div>
            <div style={{fontSize: 16, fontWeight: 600, marginTop: 2}}>{project.name}</div>
            <div style={{fontSize: 12, color: "var(--ink-3)", marginTop: 2}}>{project.customer} · หัวหน้างาน {project.lead}</div>
          </div>
          <Badge tone="info" style={{background: color, color: "white"}}>{project.status}</Badge>
        </div>
        <div style={{display: "flex", alignItems: "center", gap: 12, marginTop: 8}}>
          <div style={{flex: 1, height: 8, background: "var(--surface)", borderRadius: 999, overflow: "hidden", border: "1px solid var(--line)"}}>
            <div style={{height: "100%", width: `${project.progress}%`, background: color, borderRadius: 999}}/>
          </div>
          <span style={{fontSize: 13, fontWeight: 600}}>{project.progress}%</span>
        </div>
      </div>

      {/* KPI grid */}
      <div className="grid cols-4 mb-lg" style={{gap: 8}}>
        <KPI label="งบประมาณ" value={`฿${fmt0(project.budget)}`}/>
        <KPI label="ต้นทุนใช้ไป" value={`฿${fmt0(project.actual)}`} tone="warning"/>
        <KPI label={overBudget ? "เกินงบ" : "คงเหลือ"} value={`฿${fmt0(Math.abs(left))}`} tone={overBudget ? "danger" : "success"}/>
        <KPI label="กำไรคาดการณ์" value={`฿${fmt0(left * 0.85)}`} tone="success"/>
      </div>

      <div className="grid cols-3 mb-lg" style={{gap: 8}}>
        <KPI label="เริ่ม" value={fmtThaiDate(project.start)}/>
        <KPI label="ครบกำหนด" value={fmtThaiDate(project.end)} tone={project.progress < 100 && remaining < 7 ? "warning" : ""}/>
        <KPI label="ระยะเวลา" value={`${days} วัน · เหลือ ${Math.max(0, remaining)}`}/>
      </div>

      {/* Work orders */}
      <Card title="ใบสั่งงาน · Work Orders" sub={`${workOrders.length} ใบ`} className="mb-lg" flush
        right={<Btn size="sm" icon={I.plus} onClick={() => setShowWO(true)}>ออกใบสั่งงาน</Btn>}>
        {workOrders.length === 0 ? (
          <div style={{padding: 16, textAlign: "center", color: "var(--ink-3)", fontSize: 12.5}}>ยังไม่มีใบสั่งงาน — กด "ออกใบสั่งงาน" เพื่อกำหนดผู้รับผิดชอบ รายละเอียดงาน และกำหนดส่ง</div>
        ) : (
          <table className="t">
            <thead><tr><th>เลขที่</th><th>ผู้รับผิดชอบ</th><th>รายละเอียด</th><th>กำหนดส่ง</th><th>ความสำคัญ</th><th></th></tr></thead>
            <tbody>
              {workOrders.map((wo, i) => (
                <tr key={wo.no + i}>
                  <td className="mono">{wo.no}</td>
                  <td>{wo.assignee}</td>
                  <td style={{maxWidth: 220, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}} className="muted">{wo.detail}</td>
                  <td>{PX.pxThaiDate(wo.due)}</td>
                  <td><Badge tone={wo.priority === "ด่วนมาก" ? "danger" : wo.priority === "ด่วน" ? "warning" : "outline"}>{wo.priority}</Badge></td>
                  <td>
                    <div style={{display: "flex", gap: 2}}>
                      <button className="icon-btn" title="ออกใบประเมินงาน" onClick={() => setEvalFor(wo)}><I.sparkle size={13}/></button>
                      <button className="icon-btn" title="พิมพ์ใบสั่งงาน" onClick={() => PX.printWorkOrderDoc(project, wo)}><I.print size={13}/></button>
                      <button className="icon-btn" title="ลบ" onClick={async () => {
                        const ok = await window.confirmDelete(`ใบสั่งงาน ${wo.no}`, wo.detail.slice(0, 60));
                        if (!ok) return;
                        const list = workOrders.filter((_, j) => j !== i);
                        setWorkOrders(list);
                        PX.pxSet(project.code, { workOrders: list });
                      }}><I.trash size={13}/></button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </Card>

      {/* ใบประเมินงาน */}
      <Card title="ใบประเมินงาน · Evaluations" sub={`${evals.length} ใบ · ออกหลังงานเสร็จ — คะแนนรวมเข้า KPI อัตโนมัติ`} className="mb-lg" flush>
        {evals.length === 0 ? (
          <div style={{padding: 14, textAlign: "center", color: "var(--ink-3)", fontSize: 12.5}}>ยังไม่มีใบประเมินงาน — กดปุ่ม ✧ ที่ใบสั่งงานด้านบนเพื่อให้คะแนนผู้รับผิดชอบ</div>
        ) : (
          <table className="t">
            <thead><tr><th>เลขที่</th><th>ใบสั่งงาน</th><th>วันที่</th><th>ผู้ถูกประเมิน</th><th className="right">คะแนนเฉลี่ย</th><th></th></tr></thead>
            <tbody>
              {evals.map(ev => (
                <tr key={ev.no}>
                  <td className="mono">{ev.no}</td>
                  <td className="mono muted">{ev.woNo}</td>
                  <td>{ev.date}</td>
                  <td className="muted" style={{fontSize: 12, maxWidth: 200, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap"}}>{ev.rows.map(r => r.name).join(", ")}</td>
                  <td className="right"><b style={{color: ev.avg >= 4 ? "var(--success)" : ev.avg >= 3 ? "var(--warning)" : "var(--danger)"}}>{Number(ev.avg).toFixed(1)}/5</b></td>
                  <td>
                    <div style={{display: "flex", gap: 2, justifyContent: "flex-end"}}>
                      <button className="icon-btn" title="พิมพ์ใบประเมิน" onClick={() => window.printWorkEvalDoc && window.printWorkEvalDoc(ev)}><I.print size={13}/></button>
                      <button className="icon-btn" title="ลบ" onClick={async () => {
                        const ok = await window.confirmDelete(`ใบประเมินงาน ${ev.no}`, ev.woNo);
                        if (!ok) return;
                        window.WorkEvalStore.remove(ev.no);
                        setEvals(window.WorkEvalStore.byProject(project.code));
                      }}><I.trash size={13}/></button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </Card>

      {/* Status updates */}
      <Card title="ความคืบหน้า · Status Updates" sub={`${updates.length} รายการ · ต้องแนบรูปทุกครั้งที่อัปเดต`} className="mb-lg">
        <div style={{padding: 14, background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 8, marginBottom: 12}}>
          <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8}}>
            <div className="label">ความคืบหน้าปัจจุบัน</div>
            <div style={{fontSize: 22, fontWeight: 700, color, fontVariantNumeric: "tabular-nums"}}>{progress}%</div>
          </div>
          <div style={{position: "relative", marginBottom: 6}}>
            <input
              type="range" min="0" max="100" step="1" value={progress}
              onChange={e => setProgress(+e.target.value)}
              className="progress-range"
              style={{
                width: "100%", height: 18, cursor: "pointer",
                appearance: "none", WebkitAppearance: "none",
                background: `linear-gradient(to right, ${color} 0%, ${color} ${progress}%, var(--surface-3) ${progress}%, var(--surface-3) 100%)`,
                borderRadius: 999,
                outline: "none"
              }}
            />
          </div>
          <div style={{display: "flex", justifyContent: "space-between", fontSize: 10, color: "var(--ink-3)", marginBottom: 12, padding: "0 2px"}}>
            {[0, 25, 50, 75, 100].map(t => (
              <button key={t} onClick={() => setProgress(t)} style={{background: "transparent", border: 0, color: progress >= t ? color : "var(--ink-3)", cursor: "pointer", fontSize: 10, fontWeight: progress === t ? 700 : 400, padding: 0}}>{t}%</button>
            ))}
          </div>

          <div style={{display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 10}}>
            <div className="field"><label style={{fontSize: 11, color: "var(--ink-3)", marginBottom: 4, display: "block"}}>สถานะ</label>
              <select className="input" value={statusVal} onChange={e=>setStatusVal(e.target.value)} style={{height: 32}}>
                <option>ร่าง</option>
                <option>ออกแบบ 3D</option>
                <option>กำลังผลิต</option>
                <option>ตรวจสอบคุณภาพ</option>
                <option>รอเก็บเงิน</option>
                <option>ส่งงาน</option>
              </select>
            </div>
            <div style={{display: "flex", alignItems: "flex-end", gap: 6}}>
              {[25, 50, 75, 100].map(t => (
                <button key={t} onClick={() => setProgress(t)}
                  className="btn sm"
                  style={{flex: 1, ...(progress === t ? {background: color, color: "white", border: 0} : {})}}>
                  {t}%
                </button>
              ))}
            </div>
          </div>

          <div style={{display: "flex", flexDirection: "column", gap: 8}}>
            <textarea className="textarea" placeholder="พิมพ์โน้ตอัปเดต (ไม่บังคับ)…" value={updateText} onChange={e=>setUpdateText(e.target.value)} style={{minHeight: 60}}/>
            <div style={{display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap"}}>
              <Btn size="sm" icon={I.camera} onClick={() => setShowCam(true)}>ถ่ายรูป</Btn>
              <label className="btn sm" style={{cursor: "pointer"}}>
                <I.paperclip className="icon" size={13}/>
                แนบรูป
                <input type="file" accept="image/*" multiple style={{display: "none"}} onChange={onPickFile}/>
              </label>
              <span style={{fontSize: 11, color: photos.length === 0 ? "var(--warning)" : "var(--success)", fontWeight: 500}}>
                {photos.length === 0 ? "* ต้องมีรูป ณ ตอนอัพเดทอย่างน้อย 1 รูป" : `✓ ${photos.length} รูปพร้อมบันทึก`}
              </span>
              <span className="spacer"/>
              <Btn kind="primary" icon={I.check} onClick={addUpdate}>บันทึกอัปเดต</Btn>
            </div>
            {photos.length > 0 && (
              <div style={{display: "flex", gap: 6, flexWrap: "wrap"}}>
                {photos.map((p, i) => (
                  <div key={i} style={{position: "relative", width: 60, height: 60, borderRadius: 4, overflow: "hidden", border: "1px solid var(--line)"}}>
                    <img src={p.url} alt={p.name} style={{width: "100%", height: "100%", objectFit: "cover"}}/>
                    <button onClick={() => setPhotos(ph => ph.filter((_, j) => j !== i))}
                      style={{position: "absolute", top: 2, right: 2, width: 16, height: 16, padding: 0, borderRadius: "50%", background: "rgba(0,0,0,0.7)", color: "white", border: 0, cursor: "pointer", fontSize: 10}}>×</button>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Timeline */}
        <div style={{position: "relative", paddingLeft: 18}}>
          <div style={{position: "absolute", left: 6, top: 6, bottom: 6, width: 2, background: "var(--line)"}}/>
          {updates.map((u, i) => (
            <div key={i} style={{position: "relative", padding: "10px 0", display: "flex", gap: 10}}>
              <div style={{position: "absolute", left: -16, top: 14, width: 14, height: 14, borderRadius: "50%", background: u.type === "complete" ? "var(--success)" : u.type === "issue" ? "var(--danger)" : u.type === "milestone" ? color : "var(--ink-4)", border: "3px solid var(--surface)"}}/>
              <div style={{flex: 1}}>
                <div style={{fontSize: 13}}>
                  <span style={{marginRight: 4}}>{UPDATE_ICONS[u.type] || "•"}</span>
                  <b>{u.who}</b> · <span>{u.text}</span>
                </div>
                <div style={{fontSize: 11, color: "var(--ink-3)", marginTop: 2}}>{fmtThaiDate(u.date)}</div>
                {u.progressTo !== undefined && u.progressFrom !== undefined && u.progressTo !== u.progressFrom && (
                  <div style={{marginTop: 6, padding: "5px 9px", background: color + "18", borderRadius: 4, fontSize: 11, color: color, display: "inline-flex", alignItems: "center", gap: 6}}>
                    📈 {u.progressFrom}% → <b>{u.progressTo}%</b>
                  </div>
                )}
                {u.photos && u.photos.length > 0 && (
                  <div style={{display: "flex", gap: 6, flexWrap: "wrap", marginTop: 8}}>
                    {u.photos.map((p, j) => (
                      <img key={j} src={p.url} alt={p.name}
                        style={{width: 80, height: 80, objectFit: "cover", borderRadius: 4, border: "1px solid var(--line)", cursor: "pointer"}}
                        onClick={() => window.open(p.url, "_blank")}/>
                    ))}
                  </div>
                )}
              </div>
            </div>
          ))}
        </div>
      </Card>

      {/* Project photo gallery */}
      <Card title="รูปภาพโปรเจกต์ · Photos" sub={`${gallery.length} รูป`} className="mb-lg"
        right={<div style={{display: "flex", gap: 6}}>
          <Btn size="sm" icon={I.camera} onClick={() => setGalleryCam(true)}>ถ่ายรูป</Btn>
          <label className="btn sm" style={{cursor: "pointer"}}>
            <input type="file" accept="image/*" multiple style={{display: "none"}} onChange={onPickGallery}></input>
            อัพโหลดรูป
          </label>
        </div>}>
        {gallery.length === 0 ? (
          <div style={{padding: 18, textAlign: "center", color: "var(--ink-3)", fontSize: 12.5, border: "1.5px dashed var(--line-strong)", borderRadius: 8, background: "var(--surface-2)"}}>
            ยังไม่มีรูปในโปรเจกต์ — อัพโหลดรูปแบบ, หน้างาน, ผลงาน ได้ที่นี่
          </div>
        ) : (
          <div style={{display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(96px, 1fr))", gap: 8}}>
            {gallery.map((g, i) => (
              <div key={i} style={{position: "relative", aspectRatio: "1", borderRadius: 6, overflow: "hidden", border: "1px solid var(--line)"}}>
                <img src={g.url} alt={g.name} style={{width: "100%", height: "100%", objectFit: "cover", cursor: "pointer"}} onClick={() => window.open(g.url, "_blank")}/>
                <button onClick={() => saveGallery(gallery.filter((_, j) => j !== i))}
                  style={{position: "absolute", top: 3, right: 3, width: 18, height: 18, padding: 0, borderRadius: "50%", background: "rgba(0,0,0,0.72)", color: "white", border: 0, cursor: "pointer", fontSize: 11, lineHeight: "16px"}}>×</button>
              </div>
            ))}
          </div>
        )}
      </Card>

      {/* Expenses */}
      <Card title="ค่าใช้จ่ายของโปรเจกต์" sub={`${expenses.length + extraExpenses.length} รายการ · รวม ฿${fmt0(totalExpense)}`} className="mb-lg" right={<Btn size="sm" icon={I.plus} onClick={() => setShowExp(true)}>เพิ่มค่าใช้จ่าย</Btn>} flush>
        {(expenses.length + extraExpenses.length) === 0 ? (
          <div style={{padding: 16, textAlign: "center", color: "var(--ink-3)", fontSize: 12.5}}>ยังไม่มีค่าใช้จ่ายที่ผูกกับโปรเจกต์นี้</div>
        ) : (
          <table className="t">
            <thead><tr><th>เลขที่</th><th>วันที่</th><th>หมวด</th><th>เจ้าหนี้</th><th className="right">ยอด</th><th>สถานะ</th></tr></thead>
            <tbody>
              {expenses.map(e => (
                <tr key={e.no}>
                  <td className="mono">{e.no}</td>
                  <td>{e.date}</td>
                  <td>{e.category}</td>
                  <td className="muted">{e.vendor}</td>
                  <td className="right amount">฿{fmt0(e.amount)}</td>
                  <td><Badge>{e.status}</Badge></td>
                </tr>
              ))}
              {extraExpenses.map((e, i) => (
                <tr key={"x" + i}>
                  <td className="mono muted">—</td>
                  <td>{e.date}</td>
                  <td>{e.category}</td>
                  <td className="muted">{e.vendor}</td>
                  <td className="right amount">฿{fmt0(+e.amount || 0)}</td>
                  <td><Badge tone="info">{e.status}</Badge></td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
        <table className="t" style={{borderTop: "1px solid var(--line)"}}>
          <tbody>
            <tr><td>วัตถุดิบที่เบิกใช้</td><td className="muted" style={{fontSize: 12}}>SS304-SH-1.0 (4 แผ่น)</td><td colSpan={2}></td><td className="right amount">฿11,400</td><td><Badge tone="info">เบิกแล้ว</Badge></td></tr>
            <tr><td>ค่าจ้าง / OT</td><td className="muted" style={{fontSize: 12}}>วิทยา + สมศักดิ์ + ประยุทธ</td><td colSpan={2}></td><td className="right amount">฿{fmt0(Math.round(project.actual * 0.4))}</td><td><Badge tone="info">ลงเวลาแล้ว</Badge></td></tr>
            <tr><td>ค่าบริการภายนอก</td><td className="muted" style={{fontSize: 12}}>ชุบ/พ่นสี (subcontract)</td><td colSpan={2}></td><td className="right amount">฿{fmt0(Math.round(project.actual * 0.15))}</td><td><Badge tone="warning">รออนุมัติ</Badge></td></tr>
          </tbody>
        </table>
      </Card>

      {/* Summary */}
      <Card title="สรุปโปรเจกต์ · Summary" className="mb-lg" right={<Btn size="sm" icon={I.print} onClick={() => PX.printJobSummaryDoc(project)}>พิมพ์ใบสรุปงาน</Btn>}>
        <table style={{width: "100%", fontSize: 13}}>
          <tbody>
            <tr><td className="muted" style={{padding: "6px 0"}}>มูลค่างาน (Revenue)</td><td className="right amount">฿{fmt0(project.budget)}</td></tr>
            <tr><td className="muted" style={{padding: "6px 0"}}>ต้นทุนรวม (ปัจจุบัน)</td><td className="right amount">฿{fmt0(project.actual)}</td></tr>
            <tr><td className="muted" style={{padding: "6px 0"}}>ค่าใช้จ่ายที่เบิก/ผูก</td><td className="right amount">฿{fmt0(totalExpense)}</td></tr>
            <tr style={{borderTop: "1px solid var(--line)"}}><td style={{padding: "8px 0", fontWeight: 600}}>กำไรขั้นต้น</td><td className="right amount" style={{fontWeight: 600, color: overBudget ? "var(--danger)" : "var(--success)"}}>฿{fmt0(left)}</td></tr>
            <tr><td className="muted" style={{padding: "6px 0"}}>Margin</td><td className="right amount" style={{color: overBudget ? "var(--danger)" : "var(--ink-1)"}}>{project.budget > 0 ? ((left / project.budget) * 100).toFixed(1) : "0.0"}%</td></tr>
            <tr><td className="muted" style={{padding: "6px 0"}}>ความคืบหน้า vs เวลาที่ผ่าน</td><td className="right">
              <span style={{color: project.progress >= (elapsed/days*100) ? "var(--success)" : "var(--warning)"}}>
                {project.progress}% / เวลาผ่าน {Math.round(elapsed/days*100)}%
              </span>
            </td></tr>
            <tr><td className="muted" style={{padding: "6px 0"}}>เอกสารที่เกี่ยวข้อง</td><td className="right" style={{fontSize: 12}}>
              <span className="badge outline mono" style={{marginLeft: 4}}>{project.code.replace("JOB", "QO")}</span>
              <span className="badge outline mono" style={{marginLeft: 4}}>{project.code.replace("JOB", "INV")}</span>
            </td></tr>
          </tbody>
        </table>
      </Card>

      {/* Sub-modals */}
      {showCam && window.CameraCaptureModal && (
        <window.CameraCaptureModal onClose={() => setShowCam(false)} onCapture={(url) => setPhotos(p => [...p, { url, name: "camera-" + Date.now() }].slice(0, 6))}/>
      )}
      {galleryCam && window.CameraCaptureModal && (
        <window.CameraCaptureModal onClose={() => setGalleryCam(false)} onCapture={(url) => saveGallery([...gallery, { url, name: "camera-" + Date.now(), date: PX.pxToday() }])}/>
      )}
      {showWO && <window.WorkOrderModal project={project} onClose={() => setShowWO(false)} onSaved={(list) => setWorkOrders(list)}/>}
      {evalFor && window.WorkEvalModal && <window.WorkEvalModal project={project} wo={evalFor} onClose={() => setEvalFor(null)} onSaved={() => setEvals(window.WorkEvalStore.byProject(project.code))}/>}
      {showEdit && <window.ProjectFormModal project={project} onClose={() => setShowEdit(false)} onSaved={(rec) => { Object.assign(project, rec); onChanged && onChanged(); }}/>}
      {showExp && <window.ProjectExpenseModal project={project} onClose={() => setShowExp(false)} onSaved={(list) => setExtraExpenses(list)}/>}
    </Drawer>
  );
}

function KPI({ label, value, tone }) {
  const c = tone === "success" ? "var(--success)" : tone === "warning" ? "var(--warning)" : tone === "danger" ? "var(--danger)" : "var(--ink-1)";
  return (
    <div style={{padding: 10, background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 6}}>
      <div className="label">{label}</div>
      <div style={{fontSize: 16, fontWeight: 600, marginTop: 2, color: c, fontVariantNumeric: "tabular-nums"}}>{value}</div>
    </div>
  );
}

// =============== Main Projects page ===============
function ProjectsPage({ navigate }) {
  const D = window.SSSData;
  const PX = window.ProjX;
  const { Btn, Badge, Card, PageHead, Tabs, fmt0 } = window.UI;

  const mergeAll = () => {
    const users = PX.upLoad();
    const base = D.Projects.filter(p => !users.some(u => u.code === p.code));
    return [...users, ...base].map(p => {
      const x = PX.pxGet(p.code);
      return { ...p, ...(x.fields || {}), progress: x.progress !== undefined ? x.progress : p.progress, status: x.status || p.status };
    });
  };

  const [projects, setProjects] = useStateP3(mergeAll);
  const refresh = () => setProjects(mergeAll());
  const [tab, setTab] = useStateP3("gantt");
  const [selected, setSelected] = useStateP3(null);
  const [showNew, setShowNew] = useStateP3(false);
  const [woFor, setWoFor] = useStateP3(null);
  const [monthDate, setMonthDate] = useStateP3(new Date(2026, 4, 1)); // May 2026
  const changeMonth = (dir) => {
    if (dir === "today") setMonthDate(new Date(2026, 4, 1));
    else setMonthDate(d => new Date(d.getFullYear(), d.getMonth() + dir, 1));
  };

  const totalBudget = projects.reduce((s, p) => s + p.budget, 0);
  const totalActual = projects.reduce((s, p) => s + p.actual, 0);
  const active = projects.filter(p => p.status !== "ส่งงาน" && p.progress < 100).length;

  const exportJobCosting = () => {
    window.exportRowsCSV && window.exportRowsCSV("job-costing", [
      { key: "code", label: "รหัส" }, { key: "name", label: "โปรเจกต์" }, { key: "customer", label: "ลูกค้า" },
      { key: "lead", label: "หัวหน้างาน" }, { key: "budget", label: "งบประมาณ" }, { key: "actual", label: "ต้นทุนใช้ไป" },
      { key: "progress", label: "ความคืบหน้า %" }, { key: "status", label: "สถานะ" }, { key: "due", label: "ครบกำหนด" }
    ], projects);
    window.toast && window.toast("ส่งออกรายงาน Job Costing แล้ว");
  };

  return (
    <>
      <PageHead title="โปรเจกต์/งาน · Job Costing" sub="Timeline แบบ Gantt · ใบสั่งงาน · อัปเดตสถานะพร้อมรูป · สรุปค่าแรง-ค่าวัสดุ"
        right={<>
          <Btn icon={I.download} kind="ghost" onClick={exportJobCosting}>รายงาน Job Costing</Btn>
          <Btn icon={I.plus} kind="primary" onClick={() => setShowNew(true)}>สร้างโปรเจกต์</Btn>
        </>}/>

      <div className="grid cols-4 mb-lg">
        <window.UI.Stat label="โปรเจกต์เปิดอยู่" value={active} icon={I.briefcase}/>
        <window.UI.Stat label="งบประมาณรวม" value={`฿${fmt0(totalBudget)}`} sub="WIP value" icon={I.calc}/>
        <window.UI.Stat label="ต้นทุนใช้ไป" value={`฿${fmt0(totalActual)}`} sub={totalBudget > 0 ? `${(totalActual/totalBudget*100).toFixed(0)}% ของงบ` : ""} icon={I.receipt}/>
        <window.UI.Stat label="กำไรขั้นต้นโดยรวม" value={`฿${fmt0(totalBudget - totalActual)}`} sub={totalBudget > 0 ? `Margin ${((1 - totalActual/totalBudget) * 100).toFixed(1)}%` : ""} dir="up" icon={I.money}/>
      </div>

      <Tabs items={[
        { key: "gantt", label: "Gantt Timeline", count: projects.length },
        { key: "calendar", label: "ปฏิทินรายเดือน" },
        { key: "board", label: "Status Board" },
        { key: "list", label: "ตาราง" }
      ]} active={tab} onChange={setTab}/>

      {tab === "gantt" && (
        <Card title="ไทม์ไลน์โปรเจกต์" sub="คลิกแถบเพื่อดูรายละเอียด · เส้นประแดง = วันนี้">
          <GanttChart projects={projects} onSelect={setSelected}/>
          <div style={{display: "flex", gap: 14, marginTop: 14, fontSize: 11.5, flexWrap: "wrap"}}>
            {Object.entries(STATUS_COLORS).map(([s, c]) => (
              <div key={s} style={{display: "flex", alignItems: "center", gap: 6, color: "var(--ink-3)"}}>
                <div style={{width: 12, height: 12, background: c, borderRadius: 3}}/>
                {s}
              </div>
            ))}
          </div>
        </Card>
      )}

      {tab === "calendar" && (
        <Card title="ปฏิทินโปรเจกต์ · Calendar View" sub="คลิกแถบหรือรายชื่อด้านล่างเพื่อเปิดรายละเอียด">
          <MonthCalendar projects={projects} monthDate={monthDate} onChangeMonth={changeMonth} onSelect={setSelected}/>
          <div style={{display: "flex", gap: 14, marginTop: 14, fontSize: 11.5, flexWrap: "wrap"}}>
            {Object.entries(STATUS_COLORS).map(([s, c]) => (
              <div key={s} style={{display: "flex", alignItems: "center", gap: 6, color: "var(--ink-3)"}}>
                <div style={{width: 12, height: 12, background: c, borderRadius: 3}}/>
                {s}
              </div>
            ))}
          </div>
        </Card>
      )}

      {tab === "board" && (
        <div style={{display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 10}}>
          {["ออกแบบ 3D", "กำลังผลิต", "ตรวจสอบคุณภาพ", "รอเก็บเงิน", "ส่งงาน"].map(col => {
            const items = projects.filter(p => p.status === col);
            const color = STATUS_COLORS[col];
            return (
              <div key={col} style={{background: "var(--surface-2)", borderRadius: 8, padding: 8, minHeight: 200}}>
                <div style={{display: "flex", alignItems: "center", gap: 6, padding: "4px 6px", marginBottom: 8}}>
                  <div style={{width: 8, height: 8, borderRadius: 2, background: color}}/>
                  <span style={{fontSize: 12, fontWeight: 600}}>{col}</span>
                  <span style={{fontSize: 11, color: "var(--ink-3)", marginLeft: "auto"}}>{items.length}</span>
                </div>
                {items.map(p => (
                  <div key={p.code} onClick={() => setSelected(p)} style={{padding: 10, background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 6, marginBottom: 6, cursor: "pointer", borderLeft: `3px solid ${color}`}}>
                    <div className="mono" style={{fontSize: 10, color: "var(--ink-3)"}}>{p.code}</div>
                    <div style={{fontSize: 12, fontWeight: 500, marginTop: 2}}>{p.name.length > 40 ? p.name.slice(0,40)+"…" : p.name}</div>
                    <div style={{fontSize: 11, color: "var(--ink-3)", marginTop: 2}}>{p.customer}</div>
                    <div style={{height: 4, background: "var(--surface-3)", borderRadius: 999, marginTop: 8, overflow: "hidden"}}>
                      <div style={{height: "100%", width: `${p.progress}%`, background: color, borderRadius: 999}}/>
                    </div>
                    <div style={{display: "flex", justifyContent: "space-between", marginTop: 6, fontSize: 10.5, color: "var(--ink-3)"}}>
                      <span>฿{fmt0(p.actual/1000)}k / ฿{fmt0(p.budget/1000)}k</span>
                      <span>ครบ {p.due.split(" ").slice(0,2).join(" ")}</span>
                    </div>
                  </div>
                ))}
              </div>
            );
          })}
        </div>
      )}

      {tab === "list" && (
        <Card flush>
          <table className="t">
            <thead><tr><th>รหัส</th><th>โปรเจกต์</th><th>ลูกค้า</th><th>หัวหน้างาน</th><th className="right">งบประมาณ</th><th className="right">ใช้ไป</th><th className="right">คงเหลือ</th><th>ความคืบหน้า</th><th>ครบกำหนด</th><th>สถานะ</th></tr></thead>
            <tbody>
              {projects.map(p => {
                const left = p.budget - p.actual;
                const overBudget = p.actual > p.budget;
                return (
                  <tr key={p.code} className="row-clickable" onClick={() => setSelected(p)}>
                    <td className="mono">{p.code}</td>
                    <td>{p.name}</td>
                    <td className="muted">{p.customer}</td>
                    <td>{p.lead}</td>
                    <td className="right amount">฿{fmt0(p.budget)}</td>
                    <td className="right amount">฿{fmt0(p.actual)}</td>
                    <td className="right amount" style={{color: overBudget ? "var(--danger)" : "var(--ink-1)"}}>฿{fmt0(left)}</td>
                    <td style={{minWidth: 140}}><window.ProgressBar pct={p.progress}/></td>
                    <td className="muted">{p.due}</td>
                    <td><Badge>{p.status}</Badge></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </Card>
      )}

      {selected && <ProjectDetailDrawer project={selected} onClose={() => { setSelected(null); refresh(); }} onChanged={refresh}/>}

      {showNew && <window.ProjectFormModal onClose={() => setShowNew(false)} onSaved={(rec, thenWO) => {
        refresh();
        if (thenWO) setTimeout(() => setWoFor(rec), 150);
      }}/>}

      {woFor && <window.WorkOrderModal project={woFor} onClose={() => setWoFor(null)} onSaved={() => refresh()}/>}
    </>
  );
}

window.Projects = ProjectsPage;
