// ---- Sections ----

const fmt = (n) => n.toLocaleString("th-TH");

const LiveBadge = () => (
  <span className="live-badge">
    <i className="live-dot" aria-hidden="true" />
    Live
  </span>
);

const OverviewSection = ({ liveSales }) => {
  const liveTotal   = (liveSales || []).reduce((s, r) => s + r.amount, 0);
  const totalDone   = BASELINE.fyp + liveTotal;
  const fypProgress = Math.min(Math.round(totalDone / TARGET.fyp * 100), 100);
  const fypRemaining = Math.max(TARGET.fyp - totalDone, 0);
  const agentProgress = Math.round(BASELINE.agents / TARGET.agents * 100);
  const loading = liveSales === null;
  return (
    <section className="scene" id="overview">
      <div className="hero">
        <div>
          <Eyebrow>Krungthai-AXA Life · สำนักงาน 83G · 1 มิ.ย.–31 ธ.ค. 2569</Eyebrow>
          <h1 className="display">
            พิชิต <em>30,000,000 APE</em><br/>
            ด้วยพลังของ R.T.M.S
          </h1>
          <p className="section-sub" style={{marginBottom: 24}}>
            แผนงานเชิงระบบสำหรับผู้บริหารสำนักงานกรุงไทย-แอกซ่า 83G — ใช้กรอบ
            <strong> Recruiting · Training · Motivating · Supervising </strong>
            ขับเคลื่อน 15 Unit 110 ตัวแทน สู่เป้า 30,000,000 APE ภายในสิ้นปี 2026
          </p>
          <Countdown />
        </div>
      </div>

      <div className="kpi-row">
        <KpiCard
          feature
          label="ยอดคงเหลือที่ต้องทำ"
          value={loading ? "..." : `${(fypRemaining / 1000000).toFixed(2)} M`}
          suffix="APE"
          sub={`เป้ารวม ${TARGET.fyp.toLocaleString('en-US')} · ทำได้แล้ว ${totalDone.toLocaleString('en-US')} · ${fypProgress}% ของเป้า`}
          progress={fypProgress}
        />
        <KpiCard
          label="ตัวแทนปลายปี"
          value={TARGET.agents}
          suffix="manpower"
          sub={`ปัจจุบัน ${BASELINE.agents} manpower · ต้องเพิ่มอีก ${TARGET.agents-BASELINE.agents}`}
          progress={agentProgress}
        />
        <KpiCard
          label="Unit ปฏิบัติการ"
          value={TARGET.units}
          suffix="Unit"
          sub="เฉลี่ย ~2,000,000 APE/Unit · ~7.3 ตัวแทน/Unit"
          progress={100}
        />
      </div>
    </section>
  );
};

// --- R.T.M.S section with interactive focus ---
const RtmsSection = () => {
  const [focus, setFocus] = React.useState("R");
  const active = PILLARS.find(p => p.key === focus);
  const linkedClubs = CLUBS.filter(c => c.pillar.includes(focus.toLowerCase()));
  const linkedActs = ACTIVITIES.filter(a => a.pillar.includes(focus.toLowerCase()));

  const playbookBy = {
    R: [
      ["เป้าหมาย", "เพิ่มตัวแทน +110 manpower (0 → 110) ภายในสิ้นปี"],
      ["ช่องทางหลัก", "Open House × 24, CSR ภูเก็ต × 4, Connect Club × 24"],
      ["จุดวัด", "ผู้สนใจ/เดือน · อัตรา Convert · ตัวแทน Active ปีแรก"],
      ["จังหวะ", "เก็บ Lead ทุกสัปดาห์ → คัดกรอง → Open House → ฝึก First Stage"],
    ],
    T: [
      ["เป้าหมาย", "ตัวแทนทุกระดับมีเส้นทางพัฒนาที่ชัดเจน"],
      ["ระบบคลับ", "First Stage · ClaimHub · IC Family · Master Owner · AI Club"],
      ["จุดวัด", "ชั่วโมงเรียนเฉลี่ย/คน · ผล Skill Assessment · Production แต่ละระดับ"],
      ["จังหวะ", "6 วัน/สัปดาห์ · เช้า Mindset · ค่ำ Skill"],
    ],
    M: [
      ["เป้าหมาย", "ทีมรู้สึก 'อยากทำ' มากกว่า 'ต้องทำ' ตลอดทั้งปี"],
      ["เครื่องมือ", "Morning Mindset, Power Sync, Contest รายไตรมาส, Recognition"],
      ["จุดวัด", "Active rate, อัตราการเข้าร่วม Morning Mindset, Contest Participation"],
      ["จังหวะ", "เช้าทุกวัน · เดือนละ 1 Sync · ไตรมาสละ 1 Contest · ปลายปี Gala"],
    ],
    S: [
      ["เป้าหมาย", "ผู้จัดการเห็นข้อมูลจริงทุกสัปดาห์ ปรับเกมได้ทันที"],
      ["เครื่องมือ", "Daily Tracking Sheet · Weekly 1-on-1 · Monthly Business Review"],
      ["จุดวัด", "Activity Ratio, Closing Rate, Persistency, Production Gap"],
      ["จังหวะ", "ทุกเช้า Brief · ทุกสัปดาห์ Coach · ทุกเดือน Review Unit"],
    ],
  };

  return (
    <section className="scene" id="rtms">
      <SectionHead
        eyebrow="02 — Framework"
        title="R.T.M.S สำหรับผู้บริหารสำนักงาน"
        sub="กรอบบริหาร 4 เสาหลัก ครอบคลุมทุกกิจกรรมที่จะพา 83G ถึง 30,000,000 — คลิกแต่ละเสาเพื่อดูแผนปฏิบัติ"
      />

      <div className="rtms-grid">
        {PILLARS.map(p => (
          <button
            key={p.key}
            className={`pillar ${p.cls} ${focus===p.key?"active":""}`}
            onClick={() => setFocus(p.key)}
            style={{textAlign:'left', font:'inherit', color:'inherit'}}
          >
            <span className="pillar-letter">{p.key}</span>
            <span className="pillar-tag">{p.key} · {p.name}</span>
            <h3>{p.th}</h3>
            <p className="pillar-desc">{p.desc}</p>
            <div className="pillar-metric">
              <span className="pillar-metric-label">{p.metric.label}</span>
              <span className="pillar-metric-value">{p.metric.value}</span>
            </div>
          </button>
        ))}
      </div>

      <div className="pillar-detail">
        <div>
          <span className={`tag ${active.cls}`}>{active.key} · {active.name}</span>
          <h3>{active.th} — แผนปฏิบัติ</h3>
          <p className="lead">{active.desc}</p>
          {playbookBy[focus].map(([k, v], i) => (
            <div className="bullet" key={i}>
              <span className="b-icon">§</span>
              <span><b>{k}</b> — {v}</span>
            </div>
          ))}
        </div>
        <div>
          <div style={{fontSize:11, letterSpacing:'0.18em', textTransform:'uppercase', color:'var(--muted)', marginBottom:10}}>กิจกรรมที่ผูกกับเสานี้</div>
          <div className="linked-list">
            {[...linkedActs.map(a => ({nm:a.name, freq:a.freq, key:'a-'+a.id})),
              ...linkedClubs.map(c => ({nm:c.name, freq:`${c.day} · ${c.time}`, key:'c-'+c.id}))
            ].map(x => (
              <div className="li" key={x.key}>
                <span className="nm">{x.nm}</span>
                <span className="freq">{x.freq}</span>
              </div>
            ))}
            {linkedActs.length+linkedClubs.length === 0 && (
              <div className="li"><span className="freq">— ยังไม่ผูกกิจกรรม —</span></div>
            )}
          </div>
        </div>
      </div>
    </section>
  );
};

// --- Training Clubs section ---
const TrainingSection = () => {
  const [view, setView] = React.useState("week");
  const [liveNow, setLiveNow] = React.useState(() => new Date());
  const [adminSchedules, setAdminSchedules] = React.useState([]);
  const currentPlanMonthIndex = Math.min(Math.max(new Date().getMonth() - 5, 0), MONTHS.length - 1);
  const [monthIndex, setMonthIndex] = React.useState(currentPlanMonthIndex);
  const DAYS = ["จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"];
  const DAY_FULL = ["จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"];
  const DATE_MONTHS = ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."];
  const SLOTS = [
    { id: "morning", label: "08:30", sub: "Morning" },
    { id: "afternoon", label: "13:00", sub: "Afternoon" },
    { id: "evening", label: "20:00", sub: "Evening" },
  ];

  React.useEffect(() => {
    const timer = window.setInterval(() => setLiveNow(new Date()), 30000);
    return () => window.clearInterval(timer);
  }, []);

  React.useEffect(() => {
    sb.from("class_schedules").select("*").order("day_of_week").order("time")
      .then(({ data }) => setAdminSchedules(data || []));
  }, []);

  const adminClubs = adminSchedules.map(row => ({
    id: `admin-${row.id}`,
    name: row.title,
    desc: row.note || "ตารางเรียนที่แอดมินเพิ่ม",
    day: DAY_FULL[Number(row.day_of_week) - 1] || "-",
    dayIdx: Number(row.day_of_week),
    weeks: "ทุกสัปดาห์",
    time: row.time,
    channel: row.channel || "Online",
    owners: [],
    pillar: "t",
    perMonth: 4,
    adminManaged: true,
  }));
  const allClubs = [...CLUBS, ...adminClubs];
  const monthlyClubs = allClubs.filter(c => !c.tbd);
  const activeMonth = MONTHS[monthIndex];
  const calendarMonth = monthIndex + 5; // Jun 2026 is zero-based month 5
  const monthlyEvents = (window.CALENDAR_EVENTS || []).filter(event => {
    const date = new Date(`${event.date}T00:00:00`);
    return date.getFullYear() === 2026 && date.getMonth() === calendarMonth;
  });
  const daysInMonth = new Date(2026, calendarMonth + 1, 0).getDate();
  const firstDayIdx = new Date(2026, calendarMonth, 1).getDay() || 7;
  const leadingDays = firstDayIdx - 1;
  const dateKeyFor = (date) =>
    `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
  const clubRunsOnDate = (club, date) => {
    const dateKey = dateKeyFor(date);
    if ((club.activeFrom && dateKey < club.activeFrom) || (club.activeUntil && dateKey > club.activeUntil)) return false;
    const jsDay = date.getDay();
    const dayIdx = jsDay === 0 ? 7 : jsDay;
    const matchesDay = Array.isArray(club.dayIdx) ? club.dayIdx.includes(dayIdx) : club.dayIdx === dayIdx;
    if (!matchesDay) return false;
    const weekOfMonth = Math.floor((date.getDate() - 1) / 7) + 1;
    if (club.weeks === "ทุกสัปดาห์") return true;
    if (club.weeks.includes("สัปดาห์ที่ 3")) return weekOfMonth === 3;
    if (club.weeks.includes("2") && club.weeks.includes("4")) return weekOfMonth === 2 || weekOfMonth === 4;
    if ((club.perMonth || 0) === 2) return weekOfMonth === 1 || weekOfMonth === 3;
    if ((club.perMonth || 0) === 1) return weekOfMonth === 1;
    return true;
  };
  const sessionTimeOnDate = (hm, date) => {
    const [hour, minute] = (hm || "").split(":").map(Number);
    if (!Number.isFinite(hour) || !Number.isFinite(minute)) return null;
    const timestamp = new Date(date);
    timestamp.setHours(hour, minute, 0, 0);
    return timestamp;
  };
  const clubIsLiveOnDate = (club, date) => {
    if (!clubRunsOnDate(club, date)) return false;
    const [startHM, endHM] = (club.time || "").split(/[–-]/).map(s => s.trim());
    const start = sessionTimeOnDate(startHM, date);
    const end = sessionTimeOnDate(endHM, date);
    if (!start || !end) return false;
    if (end < start) end.setDate(end.getDate() + 1);
    return liveNow >= start && liveNow <= end;
  };
  // Weekly slot chips show the recurring schedule — they should pulse whenever
  // the class is in session right now, even if the column's date in the
  // displayed month differs from today.
  const clubIsLiveNow = (club) => clubIsLiveOnDate(club, liveNow);
  const ZOOM_OPEN_LEAD_MS = 30 * 60 * 1000;
  const clubZoomOpenOnDate = (club, date) => {
    if (!clubRunsOnDate(club, date)) return false;
    const [startHM, endHM] = (club.time || "").split(/[–-]/).map(s => s.trim());
    const start = sessionTimeOnDate(startHM, date);
    const end = sessionTimeOnDate(endHM, date);
    if (!start || !end) return false;
    if (end < start) end.setDate(end.getDate() + 1);
    return liveNow >= new Date(start.getTime() - ZOOM_OPEN_LEAD_MS) && liveNow <= end;
  };
  const timeValue = (time) => {
    const [hour = "0", minute = "0"] = (time || "").split(/[–-]/)[0].split(":");
    return Number(hour) * 60 + Number(minute);
  };
  const cellsFor = (slot, dayIdx, date) => {
    return monthlyClubs.filter(c => {
      const matchesDay = Array.isArray(c.dayIdx) ? c.dayIdx.includes(dayIdx) : c.dayIdx === dayIdx;
      if (!matchesDay || !clubRunsOnDate(c, date)) return false;
      if (c.adminManaged) {
        const start = timeValue(c.time);
        if (slot === "morning") return start < 12 * 60;
        if (slot === "afternoon") return start >= 12 * 60 && start < 18 * 60;
        if (slot === "evening") return start >= 18 * 60;
      }
      if (slot === "morning") return c.id === "morning-mindset";
      if (slot === "afternoon") return c.id === "connect";
      if (slot === "evening") return c.id !== "connect" && c.id !== "morning-mindset";
      return false;
    });
  };
  const firstClubDay = (club) => Array.isArray(club.dayIdx) ? Math.min(...club.dayIdx) : club.dayIdx;
  const tableClubs = allClubs
    .map((club, index) => ({ club, index }))
    .sort((a, b) => {
      if (a.club.id === "test-class") return -1;
      if (b.club.id === "test-class") return 1;
      return firstClubDay(a.club) - firstClubDay(b.club) || a.index - b.index;
    })
    .map(({ club }) => club);
  const weekDates = DAYS.map((_, i) => {
    const date = new Date(2026, calendarMonth, 1 - leadingDays + i);
    return `${date.getDate()} ${DATE_MONTHS[date.getMonth()]}`;
  });
  const eventsForDate = (date) => {
    const dateKey = dateKeyFor(date);
    return monthlyEvents.filter(event => event.date === dateKey);
  };
  const weeklyEventsFor = (slot, dayIndex) => {
    const date = new Date(2026, calendarMonth, 1 - leadingDays + dayIndex);
    return eventsForDate(date)
      .filter(event => {
        const start = timeValue(event.time);
        if (slot === "morning") return start < 12 * 60;
        if (slot === "afternoon") return start >= 12 * 60 && start < 18 * 60;
        if (slot === "evening") return start >= 18 * 60;
        return false;
      });
  };
  const monthDays = [
    ...Array.from({ length: leadingDays }, (_, i) => ({ key: `blank-${i}`, blank: true })),
    ...Array.from({ length: daysInMonth }, (_, i) => {
      const day = i + 1;
      const date = new Date(2026, calendarMonth, day);
      return {
        key: `day-${day}`,
        day,
        clubs: [
          ...monthlyClubs.filter(c => clubRunsOnDate(c, date)),
          ...eventsForDate(date),
        ]
          .sort((a, b) => timeValue(a.time) - timeValue(b.time)),
      };
    }),
  ];
  const monthlySessionTotal = monthDays.reduce((total, day) => total + (day.clubs ? day.clubs.length : 0), 0);

  return (
    <section className="scene" id="training">
      <SectionHead
        eyebrow="03 — Training System"
        title="ระบบคลับเรียนรู้และตารางเรียน"
        sub="ตารางคลับและคลาสเรียนที่อัปเดตจากแผนหลักและรายการที่แอดมินจัดการ"
        right={<Legend />}
      />

      <div className="view-switch" aria-label="เลือกมุมมองตารางเรียน">
        <button type="button" className={view === "week" ? "active" : ""} onClick={() => setView("week")}>สัปดาห์</button>
        <button type="button" className={view === "month" ? "active" : ""} onClick={() => setView("month")}>เดือน</button>
      </div>

      {view === "week" ? (
        <div className="week-grid">
          <div></div>
          {DAYS.map((d, i) => (
            <div key={d} className={`week-head day-${i+1} ${i>=5?'weekend':''}`}>
              <div>{DAY_FULL[i]}</div>
              <span>{weekDates[i]}</span>
            </div>
          ))}
          {SLOTS.map(slot => (
            <React.Fragment key={slot.id}>
              <div className="time-col">
                {slot.label}
                <div style={{fontSize:9, opacity:0.6, marginTop:2}}>{slot.sub}</div>
              </div>
              {DAYS.map((d, i) => {
                const dayIdx = i + 1;
                const date = new Date(2026, calendarMonth, 1 - leadingDays + i);
                const clubs = [
                  ...cellsFor(slot.id, dayIdx, date),
                  ...weeklyEventsFor(slot.id, i),
                ].sort((a, b) => timeValue(a.time) - timeValue(b.time));
                return (
                  <div key={d+slot.id} className={`slot ${clubs.length===0?'slot-empty':''}`}>
                    {clubs.map(c => {
                      const isLive = clubIsLiveNow(c);
                      return (
                      <div key={c.id} className={`club-chip ${c.pillar} ${isLive ? 'live' : ''}`} title={c.desc}>
                        <div className="club-name">
                          {c.name}
                          {isLive && <LiveBadge />}
                        </div>
                        <div className="club-meta">
                          <span>{c.time}</span>
                          {c.weeks !== "ทุกสัปดาห์" && <span className="pill">{c.weeks}</span>}
                        </div>
                      </div>
                      );
                    })}
                  </div>
                );
              })}
            </React.Fragment>
          ))}
        </div>
      ) : (
        <div className="monthly-club-panel">
          <div className="month-picker" aria-label="เลือกเดือน">
            <button onClick={() => setMonthIndex(i => Math.max(0, i - 1))} disabled={monthIndex === 0} aria-label="เดือนก่อนหน้า">‹</button>
            <div>
              <span>{monthIndex === currentPlanMonthIndex ? "เดือนปัจจุบัน" : "เดือน"}</span>
              <strong>{activeMonth} 2569</strong>
            </div>
            <button onClick={() => setMonthIndex(i => Math.min(MONTHS.length - 1, i + 1))} disabled={monthIndex === MONTHS.length - 1} aria-label="เดือนถัดไป">›</button>
          </div>
          <article className="monthly-club-card">
            <div className="monthly-club-head">
              <span>ปฏิทินทั้งเดือน</span>
              <strong>{monthlySessionTotal} รอบเรียน</strong>
            </div>
            <div className="month-calendar">
              {DAY_FULL.map((day, i) => (
                <div key={day} className={`month-weekday day-${i+1} ${i >= 5 ? "weekend" : ""}`}>{day}</div>
              ))}
              {monthDays.map(day => (
                <div key={day.key} className={`month-day ${day.blank ? "blank" : ""}`}>
                  {!day.blank && (
                    <>
                      <span className="month-date">{day.day} {activeMonth}</span>
                      <div className="month-events">
                        {day.clubs.map(c => {
                          const isLive = clubIsLiveOnDate(c, new Date(2026, calendarMonth, day.day));
                          return (
                          <div key={c.id} className={`month-event ${c.pillar} ${isLive ? 'live' : ''}`} title={`${c.name} · ${c.time}`}>
                            <strong>
                              {c.name}
                              {isLive && <LiveBadge />}
                            </strong>
                            <span>{c.time}</span>
                          </div>
                          );
                        })}
                      </div>
                    </>
                  )}
                </div>
              ))}
            </div>
          </article>
        </div>
      )}

      <div className="note">
        <strong>หมายเหตุ:</strong> Connect Club จัดที่สำนักงาน 83G วันเสาร์ เดือนละ 2 ครั้ง ช่วงบ่าย (13:00–16:30)
      </div>

      <div className="club-table">
        <div className="club-row header">
          <div>#</div>
          <div>คลับ</div>
          <div>วัน/รอบ</div>
          <div>เวลา</div>
          <div>ช่องทาง</div>
          <div>ผู้รับผิดชอบ</div>
        </div>
        {tableClubs.map((c, i) => {
          const inSession = clubIsLiveOnDate(c, liveNow);
          const zoomOpen = clubZoomOpenOnDate(c, liveNow);
          return (
          <div className="club-row" key={c.id}>
            <div className="num">{String(i + 1).padStart(2,'0')}</div>
            <div className="nm">
              {c.name}
              {inSession && <LiveBadge />}
              {c.needsName && <span style={{marginLeft:6, fontSize:10, color:'var(--gold)'}}>· ชื่อเสนอ</span>}
              {c.tbd && <span style={{marginLeft:6, fontSize:10, color:'var(--red)'}}>· รอข้อมูล</span>}
              <small>{c.desc}</small>
              {c.poster && (
                <a className="club-poster" href={c.poster} target="_blank" rel="noreferrer">
                  <img src={c.poster} alt={`โปสเตอร์ ${c.name}`} loading="lazy" />
                </a>
              )}
            </div>
            <div className="sched"><strong>{c.day}</strong><div style={{fontSize:11, color:'var(--muted)'}}>{c.weeks}</div></div>
            <div className="sched">{c.time}</div>
            <div className={`ch ${c.channel.includes('Offline')?'offline':''}`}>
              <span>{c.channel.includes('Offline')?'สำนักงาน':c.channel}</span>
            </div>
            <div className="owners">
              {c.owners.length > 0 ? (
                <div className="avatar-stack">
                  {c.owners.map(o => <Avatar key={o} name={o} />)}
                </div>
              ) : <span className="muted">แอดมินจัดการ</span>}
              {zoomOpen && (
                <a className="schedule-zoom-btn" href={ZOOM_URL} target="_blank" rel="noopener noreferrer"
                  style={{ marginTop: 8 }}>เข้าเรียน</a>
              )}
            </div>
          </div>
          );
        })}
      </div>
    </section>
  );
};

// Roster of all instructors aggregated from CLUBS
const InstructorRoster = () => {
  const rosterHidden = new Set([]);
  // Dedupe by normalized name; pick the cleanest variant as canonical display.
  const map = new Map();
  CLUBS.forEach(c => c.owners.forEach(o => {
    const key = normName(o);
    if (rosterHidden.has(key)) return;
    if (!map.has(key)) map.set(key, { display: o, variants: new Set([o]), clubs: new Set() });
    const entry = map.get(key);
    entry.variants.add(o);
    entry.clubs.add(c.name);
    // Prefer variant without "พี่" prefix as display
    if (/^(ผจก\.|ผอ\.)\s*[^พี่]/.test(o) && /พี่/.test(entry.display)) entry.display = o;
  }));
  const list = [...map.values()].sort((a,b) => a.display.localeCompare(b.display, 'th'));
  return (
    <div className="instructor-grid">
      {list.map(({ display, clubs }) => {
        const photo = photoOf(display);
        return (
          <div className="instructor-card" key={display}>
            {photo
              ? <span className="avatar-circle lg has-photo" style={{backgroundImage:`url("${photo}")`}}></span>
              : <span className={`avatar-circle lg avatar-c${nameHash(display)}`}>{initial(display)}</span>}
            <div>
              <div className="role">{roleOf(display)}</div>
              <div className="nm">{display}</div>
              <div className="clubs">{[...clubs].join(' · ')}</div>
            </div>
          </div>
        );
      })}
    </div>
  );
};

// --- Activities section ---
const ActivitiesSection = () => (
  <section className="scene" id="activities">
    <SectionHead
      eyebrow="04 — Core Activities"
      title="กิจกรรมหลักที่ขับเคลื่อนเป้า 30,000,000"
      sub="3 กิจกรรมเสาหลักที่สร้าง Pipeline ตัวแทนใหม่และโอกาสขายอย่างต่อเนื่องตลอดปี"
    />

    <div className="activities">
      {ACTIVITIES.map(a => (
        <div className="act-card" key={a.id}>
          <Tag pillar={a.tag.toLowerCase()}>{a.tag} · {PILLARS.find(p=>p.key===a.tag).name}</Tag>
          <h4>{a.name}</h4>
          <p>{a.desc}</p>
          <dl className="act-meta">
            <div><dt>ความถี่</dt><dd>{a.freq}</dd></div>
            <div><dt>ตลอดปี</dt><dd>{a.timesPerYear} ครั้ง</dd></div>
            <div style={{gridColumn:'1 / -1'}}><dt>KPI</dt><dd style={{fontSize:13, fontFamily:'IBM Plex Sans Thai', fontWeight:400, color:'var(--ink-soft)'}}>{a.kpi}</dd></div>
          </dl>
        </div>
      ))}
    </div>

    <div className="note">
      <strong>ยังไม่กำหนด:</strong> Contest รายไตรมาส, Recognition ประจำเดือน, Mid-Year Convention, Year-End Gala — ระบุไว้ใน Roadmap แล้ว แต่จะเติมรายละเอียดเมื่อได้ข้อมูลเพิ่ม
    </div>
  </section>
);

// --- APE Goal section ---
// Plan months: Jun(5)–Dec(11) mapped to APE_MONTHLY_PROGRESS index 0–6
const PLAN_JS_MONTHS = [5, 6, 7, 8, 9, 10, 11];

const APE_REFRESH_MS = 30000;

const apeWeekRange = () => {
  const now = getNow();
  const js = now.getDay(); // 0=Sun
  const diffToMon = js === 0 ? -6 : 1 - js;
  const mon = new Date(now); mon.setDate(now.getDate() + diffToMon);
  const sun = new Date(mon); sun.setDate(mon.getDate() + 6);
  const fmt = d => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`;
  return { from: fmt(mon), to: fmt(sun) };
};

const ApeGoalSection = ({ liveSales }) => {
  const now = getNow();
  const todayKey  = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,"0")}-${String(now.getDate()).padStart(2,"0")}`;
  const monthKey  = todayKey.slice(0, 7);
  const week      = apeWeekRange();

  const todayTotal = (liveSales || []).filter(r => r.date === todayKey).reduce((s, r) => s + r.amount, 0);
  const weekTotal  = (liveSales || []).filter(r => r.date >= week.from && r.date <= week.to).reduce((s, r) => s + r.amount, 0);
  const monthTotal = (liveSales || []).filter(r => r.date.startsWith(monthKey)).reduce((s, r) => s + r.amount, 0);

  const monthMap = {};
  (liveSales || []).forEach(r => {
    const m = new Date(r.date + "T00:00:00").getMonth();
    monthMap[m] = (monthMap[m] || 0) + r.amount;
  });

  const progress = APE_MONTHLY_PROGRESS.map((m, i) => ({
    ...m,
    achieved: liveSales ? (monthMap[PLAN_JS_MONTHS[i]] || 0) : m.achieved,
  }));

  const liveTotal      = (liveSales || []).reduce((s, r) => s + r.amount, 0);
  const grandAchieved  = BASELINE.fyp + liveTotal;
  const grandPct       = Math.min(Math.round(grandAchieved / TARGET.fyp * 100), 100);
  const grandRemaining = Math.max(TARGET.fyp - grandAchieved, 0);
  const totalAchieved  = progress.reduce((s, m) => s + m.achieved, 0);

  const loading = liveSales === null;

  return (
    <section className="scene" id="ape-goal">
      <SectionHead
        eyebrow="02 — APE Goals"
        title="เป้าหมาย APE"
        sub="ติดตามความคืบหน้าสู่เป้า 30,000,000 APE · แยกตามรายวัน รายสัปดาห์ และรายเดือน"
      />

      <div className="kpi-row">
        <KpiCard
          feature
          label="ยอดรวมที่ทำได้ทั้งหมด"
          value={loading ? "..." : `${(grandAchieved / 1000000).toFixed(2)} M`}
          suffix="APE"
          sub={`เป้า ${TARGET.fyp.toLocaleString("en-US")} · คงเหลือ ${grandRemaining.toLocaleString("en-US")} · ${grandPct}%`}
          progress={grandPct}
        />
        <KpiCard
          label="ยอดเดือนนี้"
          value={loading ? "..." : monthTotal.toLocaleString("en-US")}
          suffix="APE"
          sub={`เป้า ${APE_RATE.monthly.toLocaleString("en-US")} / เดือน`}
          progress={Math.min(Math.round(monthTotal / APE_RATE.monthly * 100), 100)}
        />
        <KpiCard
          label="ยอดสัปดาห์นี้"
          value={loading ? "..." : weekTotal.toLocaleString("en-US")}
          suffix="APE"
          sub={`เป้า ${APE_RATE.weekly.toLocaleString("en-US")} / สัปดาห์`}
          progress={Math.min(Math.round(weekTotal / APE_RATE.weekly * 100), 100)}
        />
        <KpiCard
          label="ยอดวันนี้"
          value={loading ? "..." : todayTotal.toLocaleString("en-US")}
          suffix="APE"
          sub={`เป้า ${APE_RATE.daily.toLocaleString("en-US")} / วัน`}
          progress={Math.min(Math.round(todayTotal / APE_RATE.daily * 100), 100)}
        />
      </div>

      <div className="divider-label">
        ความคืบหน้ารายเดือน
        {loading && <span style={{ fontSize: 12, color: "var(--muted)", marginLeft: 8 }}>กำลังโหลด...</span>}
      </div>
      <div className="table-wrap">
        <table className="dash-table ape-monthly-table">
          <thead>
            <tr>
              <th>เดือน</th>
              <th className="num">เป้าหมาย</th>
              <th className="num">ทำได้</th>
              <th className="num">คงเหลือ</th>
              <th style={{ width: 180, minWidth: 140 }}>ความคืบหน้า</th>
            </tr>
          </thead>
          <tbody>
            {progress.map(m => {
              const pct  = Math.min(Math.round(m.achieved / m.target * 100), 100);
              const left = Math.max(m.target - m.achieved, 0);
              const hit  = m.achieved >= m.target;
              return (
                <tr key={m.month}>
                  <td><strong>{m.month}</strong></td>
                  <td className="num" style={{ color: "var(--muted)" }}>{m.target.toLocaleString("en-US")}</td>
                  <td className="num">
                    <strong style={{ color: hit ? "var(--t)" : m.achieved > 0 ? "var(--gold)" : "inherit" }}>
                      {m.achieved.toLocaleString("en-US")}
                    </strong>
                  </td>
                  <td className="num" style={{ color: "var(--muted)", fontSize: 13 }}>
                    {left > 0 ? left.toLocaleString("en-US") : <span style={{ color: "var(--t)" }}>✓</span>}
                  </td>
                  <td>
                    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                      <div style={{ flex: 1, height: 6, background: "var(--line)", borderRadius: 4, overflow: "hidden" }}>
                        <div style={{
                          height: "100%", borderRadius: 4,
                          width: `${pct}%`,
                          background: hit ? "var(--t)" : "var(--gold)",
                          transition: "width 600ms ease",
                        }} />
                      </div>
                      <span style={{ fontSize: 12, color: "var(--muted)", minWidth: 36, textAlign: "right" }}>{pct}%</span>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
          <tfoot>
            <tr>
              <td><strong>รวม</strong></td>
              <td className="num"><strong style={{ color: "var(--muted)" }}>{progress.reduce((s, m) => s + m.target, 0).toLocaleString("en-US")}</strong></td>
              <td className="num"><strong style={{ color: "var(--gold)" }}>{totalAchieved.toLocaleString("en-US")}</strong></td>
              <td className="num"><strong>{Math.max(progress.reduce((s, m) => s + m.target, 0) - totalAchieved, 0).toLocaleString("en-US")}</strong></td>
              <td />
            </tr>
          </tfoot>
        </table>
      </div>
    </section>
  );
};

// --- Roadmap section ---
const RoadmapSection = () => {
  const monthlyPlan = [
    {
      month: "มิ.ย.",
      phase: "Kick-off",
      target: "3M APE",
      focus: "ตั้งเกม 15 Unit ให้พร้อมก่อนเร่งยอด",
      pillars: ["S", "T", "M"],
      actions: ["Kick-off + Target Setting", "เริ่ม Training Clubs ทุกคลับ", "Open House 2 ครั้ง", "Connect Club วันเสาร์ 2 ครั้ง", "Phase 1 Contest"],
      check: "ทุก Unit มีเป้ารายเดือนและ activity sheet ใช้งานจริง",
    },
    {
      month: "ก.ค.",
      phase: "Recruit & Activate",
      target: "3M APE",
      focus: "เพิ่มผู้สนใจและทำให้ตัวแทนใหม่ active",
      pillars: ["R", "T", "M"],
      actions: ["Open House 2 ครั้ง", "CSR ภูเก็ต", "First Stage + Wellness ต่อเนื่อง", "สรุปผล Phase 1 Contest"],
      check: "Lead ใหม่, ตัวแทนใหม่, และ active rate ต้องเห็นแนวโน้มขึ้น",
    },
    {
      month: "ส.ค.",
      phase: "Production Push",
      target: "3M APE",
      focus: "เร่ง production จากทีมที่เริ่มนิ่งแล้ว",
      pillars: ["T", "S", "M"],
      actions: ["เปิด Phase 2 Contest", "Weekly Coaching เข้มขึ้น", "Master Owner Club โฟกัสผู้นำ Unit", "Open House + Connect Club ตามรอบ"],
      check: "Pipeline แต่ละ Unit มี forecast ชัดเจนก่อนปิดเดือน",
    },
    {
      month: "ก.ย.",
      phase: "Mid-Year Review",
      target: "3M APE",
      focus: "ทบทวนครึ่งทางและปรับแผน Unit ที่หลุดเป้า",
      pillars: ["S", "M", "T"],
      actions: ["Mid-Project Convention", "Monthly Business Review", "ปิด Phase 2 Contest", "รีวิวคะแนน Training attendance"],
      check: "รู้ชัดว่า Unit ไหนต้องเสริม recruiting, skill, หรือ coaching",
    },
    {
      month: "ต.ค.",
      phase: "Comeback",
      target: "3M APE",
      focus: "ดึงทีมที่ตกจังหวะกลับเข้าเกม",
      pillars: ["M", "S", "R"],
      actions: ["เปิด Phase 3 Contest", "CSR ภูเก็ต", "Reactivate agent ที่เงียบ", "Open House 2 ครั้ง"],
      check: "จำนวนตัวแทน active กลับมาเพิ่ม และ gap ราย Unit ลดลง",
    },
    {
      month: "พ.ย.",
      phase: "Lock Pipeline",
      target: "3M APE",
      focus: "ล็อก pipeline ก่อนเข้าเดือนปิดเป้า",
      pillars: ["S", "T", "M"],
      actions: ["Forecast รายตัวแทน", "Weekly 1-on-1 ทุก Unit", "ปิด Phase 3 Contest", "เตรียมรายชื่อเคสปิดเดือนธันวาคม"],
      check: "มี pipeline พร้อมปิดเพียงพอสำหรับ Final 3M APE",
    },
    {
      month: "ธ.ค.",
      phase: "Finish Strong",
      target: "3M APE",
      focus: "ปิดยอดเพิ่ม 21 M APE และยกย่องทีม",
      pillars: ["M", "S"],
      actions: ["Phase 4 Finish Strong", "Daily scoreboard", "Monthly Business Review รอบสุดท้าย", "Year-End Recognition Gala"],
      check: "ปิดยอดเพิ่ม 21M APE พร้อมสรุปบทเรียนปี 2569",
    },
  ];

  return (
    <section className="scene" id="roadmap">
      <SectionHead
        eyebrow="04 — Roadmap"
        title="แผน 7 เดือน · 1 มิ.ย.–31 ธ.ค. 2569"
        sub="อ่านจากซ้ายไปขวาตามเดือน: เป้าเดือนนี้คืออะไร ต้องทำอะไร และต้องเช็คผลตรงไหน"
        right={<Legend />}
      />

      <div className="roadmap-summary">
        <div>
          <span>ยอดที่ต้องทำเพิ่ม</span>
          <strong>21 M APE</strong>
        </div>
        <div>
          <span>ช่วงเวลา</span>
          <strong>มิ.ย.–ธ.ค. 2569</strong>
        </div>
        <div>
          <span>กิจกรรมหลัก</span>
          <strong>Training · Open House · Connect · Contest</strong>
        </div>
      </div>

      <div className="month-roadmap">
        {monthlyPlan.map((m, i) => (
          <article className="month-card" key={m.month}>
            <div className="month-top">
              <div>
                <span className="month-step">{String(i+1).padStart(2, "0")}</span>
                <h3>{m.month}</h3>
              </div>
              <strong>{m.target}</strong>
            </div>
            <div className="month-phase">{m.phase}</div>
            <p>{m.focus}</p>
            <div className="month-pills">
              {m.pillars.map(p => {
                const pillar = PILLARS.find(x => x.key === p);
                return <span key={p} className={`tag ${pillar.cls}`}>{p} · {pillar.th}</span>;
              })}
            </div>
            <ul className="month-actions">
              {m.actions.map(a => <li key={a}>{a}</li>)}
            </ul>
            <div className="month-check">
              <span>เช็คผล</span>
              {m.check}
            </div>
          </article>
        ))}
      </div>
    </section>
  );
};

// --- Open LMS section ---
const LMS_ACTIVITY_PREFIX = "LMS: ";
const LMS_POINTS_PER_LESSON = 10;
const lmsTodayKey = () => {
  const d = new Date();
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
};

const LmsSection = ({ agent, onRefresh }) => {
  const storageKey = agent ? `lmsCompleted_${agent.id}` : "lmsCompleted";
  const [activeId, setActiveId] = React.useState(LMS_LESSONS[0]?.id);
  const [completed, setCompleted] = React.useState({});
  const [collapsed, setCollapsed] = React.useState({});
  const [saving, setSaving] = React.useState(false);
  const active = LMS_LESSONS.find(l => l.id === activeId) || LMS_LESSONS[0];
  const completedCount = LMS_LESSONS.filter(l => completed[l.id]).length;
  const progress = Math.round(completedCount / LMS_LESSONS.length * 100);

  React.useEffect(() => {
    let alive = true;
    (async () => {
      if (!agent?.id) {
        try { setCompleted(JSON.parse(localStorage.getItem(storageKey) || "{}")); }
        catch (e) { setCompleted({}); }
        return;
      }
      const validIds = new Set(LMS_LESSONS.map(l => l.id));
      const { data } = await sb.from("agent_activities")
        .select("note")
        .eq("agent_id", agent.id)
        .like("name", `${LMS_ACTIVITY_PREFIX}%`);
      const map = {};
      (data || []).forEach(r => { if (validIds.has(r.note)) map[r.note] = true; });

      try {
        const local = JSON.parse(localStorage.getItem(storageKey) || "{}");
        const pending = LMS_LESSONS.filter(l => local[l.id] && !map[l.id]).map(l => ({
          agent_id: agent.id,
          date: lmsTodayKey(),
          name: `${LMS_ACTIVITY_PREFIX}${l.title}`,
          points: LMS_POINTS_PER_LESSON,
          note: l.id,
        }));
        if (pending.length) {
          const { error } = await sb.from("agent_activities").insert(pending);
          if (!error) pending.forEach(r => { map[r.note] = true; });
        }
        if (Object.keys(local).length) localStorage.removeItem(storageKey);
      } catch (e) {}

      if (alive) setCompleted(map);
    })();
    return () => { alive = false; };
  }, [agent?.id]);

  const toggleComplete = async (lesson) => {
    if (!agent?.id) {
      const next = { ...completed, [lesson.id]: !completed[lesson.id] };
      setCompleted(next);
      localStorage.setItem(storageKey, JSON.stringify(next));
      return;
    }
    if (saving) return;
    const wasDone = !!completed[lesson.id];
    setCompleted(prev => ({ ...prev, [lesson.id]: !wasDone }));
    setSaving(true);
    if (wasDone) {
      const { error } = await sb.from("agent_activities")
        .delete()
        .eq("agent_id", agent.id)
        .eq("note", lesson.id)
        .like("name", `${LMS_ACTIVITY_PREFIX}%`);
      if (error) {
        setCompleted(prev => ({ ...prev, [lesson.id]: true }));
        alert("เกิดข้อผิดพลาด: " + error.message);
      } else {
        onRefresh && onRefresh();
      }
    } else {
      const { error } = await sb.from("agent_activities").insert([{
        agent_id: agent.id,
        date: lmsTodayKey(),
        name: `${LMS_ACTIVITY_PREFIX}${lesson.title}`,
        points: LMS_POINTS_PER_LESSON,
        note: lesson.id,
      }]);
      if (error) {
        setCompleted(prev => ({ ...prev, [lesson.id]: false }));
        alert("เกิดข้อผิดพลาด: " + error.message);
      } else {
        await runAchievementCheckAfterActivityChange(agent.id);
        onRefresh && onRefresh();
      }
    }
    setSaving(false);
  };
  const toggleCollapse = (mod) => setCollapsed(prev => ({ ...prev, [mod]: !prev[mod] }));

  const modules = [...new Set(LMS_LESSONS.map(l => l.module))];
  const grouped = modules.map(mod => ({
    mod,
    lessons: LMS_LESSONS.filter(l => l.module === mod),
  }));

  const IconPlay = () => (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="8" stroke="currentColor" strokeWidth="1.4"/>
      <polygon points="7.5,6 13,9 7.5,12" fill="currentColor"/>
    </svg>
  );
  const IconCheck = () => (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="8" stroke="currentColor" strokeWidth="1.4"/>
      <polyline points="5.5,9 8,11.5 12.5,6.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  );
  const IconChevron = ({ open }) => (
    <svg className={`lms-group-chevron${open ? " open" : ""}`} width="14" height="14" viewBox="0 0 14 14" fill="none">
      <polyline points="3,5 7,9 11,5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  );

  return (
    <section className="scene" id="lms">
      <SectionHead
        eyebrow="03 — LMS"
        title="ระบบเรียนรู้ด้วยตัวเอง"
        sub="เปิดเข้ามาเรียนได้ทันที เลือกบทเรียน ดูเนื้อหา และติ๊กเรียนจบได้ใน browser เครื่องนี้"
      />

      <div className="lms-shell">
        <div className="lms-player">
          <div className="lesson-screen">
            {active.videoUrl ? (
              <video
                key={active.videoUrl}
                controls
                controlsList="nodownload"
                style={{position:"absolute",inset:0,width:"100%",height:"100%",background:"#000"}}
              >
                <source src={active.videoUrl} type="video/mp4" />
              </video>
            ) : (
              <div style={{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:10,color:"rgba(246,241,230,0.4)"}}>
                <svg width="48" height="48" viewBox="0 0 48 48" fill="none"><circle cx="24" cy="24" r="22" stroke="currentColor" strokeWidth="2"/><polygon points="19,15 37,24 19,33" fill="currentColor"/></svg>
                <span style={{fontSize:13}}>ยังไม่มีวิดีโอ</span>
              </div>
            )}
          </div>

          <div className="lesson-main">
            <div className="lesson-head">
              <Tag pillar="t">Open Access</Tag>
              <span className="lesson-meta">{active.module} · {active.duration}</span>
            </div>
            <h3>{active.title}</h3>
            <p className="lesson-desc">{active.desc}</p>
            <button className={`complete-btn ${completed[active.id] ? "done" : ""}`}
              onClick={() => toggleComplete(active)} disabled={saving}>
              {completed[active.id] ? "✓ เรียนจบแล้ว" : "ติ๊กว่าเรียนจบ"}
            </button>

            <div className="lesson-divider" />

            <h4 className="lesson-section-title">เรียนแล้วทำได้</h4>
            <ul className="lesson-outcomes">
              {active.outcomes.map(item => <li key={item}>{item}</li>)}
            </ul>

            <div className="lesson-divider" />

            <h4 className="lesson-section-title">เอกสารประกอบ</h4>
            <div className="resource-list">
              {active.resources.map(item => <span key={item}>{item}</span>)}
            </div>
          </div>
        </div>

        <aside className="lms-lessons" aria-label="Lesson list">
          <div className="lms-sidebar-head">
            <strong>Course Content</strong>
            <span>{completedCount}/{LMS_LESSONS.length} บทเรียน</span>
          </div>
          <div className="lms-progress-bar"><div style={{width:`${progress}%`}}></div></div>

          {grouped.map(({ mod, lessons }) => {
            const doneMod = lessons.filter(l => completed[l.id]).length;
            const totalMin = lessons.reduce((sum, l) => {
              const m = l.duration.match(/(\d+)/);
              return sum + (m ? parseInt(m[1]) : 0);
            }, 0);
            const isOpen = !collapsed[mod];
            return (
              <div key={mod} className="lms-group">
                <button className="lms-group-head" onClick={() => toggleCollapse(mod)}>
                  <div>
                    <strong>{mod}</strong>
                    <span>{doneMod}/{lessons.length} · {totalMin} นาที</span>
                  </div>
                  <IconChevron open={isOpen} />
                </button>
                {isOpen && lessons.map((lesson) => {
                  const globalIdx = LMS_LESSONS.indexOf(lesson);
                  const isDone = !!completed[lesson.id];
                  const isActive = active.id === lesson.id;
                  return (
                    <button
                      key={lesson.id}
                      className={`lms-lesson${isActive ? " active" : ""}${isDone ? " done" : ""}`}
                      onClick={() => setActiveId(lesson.id)}
                    >
                      <div className="lms-lesson-text">
                        <b>{String(globalIdx + 1).padStart(2, "0")}: {lesson.title}</b>
                        <small>{isDone ? "เรียนจบแล้ว" : lesson.duration}</small>
                      </div>
                      <span className="lms-lesson-icon">
                        {isDone ? <IconCheck /> : <IconPlay />}
                      </span>
                    </button>
                  );
                })}
              </div>
            );
          })}
        </aside>
      </div>
    </section>
  );
};

Object.assign(window, { OverviewSection, ApeGoalSection, RtmsSection, TrainingSection, ActivitiesSection, RoadmapSection, LmsSection });
