/* global React, window */
// FACE/OS alternate shells: PASS (mobile employee card) + TERMINAL (kiosk).
const { useState: useModeState, useEffect: useModeEffect } = React;

function initialsOf(emp) {
  if (!emp) return '—';
  const a = (emp.first_name || '').trim();
  const b = (emp.last_name || '').trim();
  if (a || b) return ((a[0] || '') + (b[0] || '')).toUpperCase() || a.slice(0, 2).toUpperCase();
  return (emp.employee_name || emp.name || '—').slice(0, 2).toUpperCase();
}
function nameOf(emp) {
  if (!emp) return '—';
  return `${emp.first_name || ''} ${emp.last_name || ''}`.trim() || emp.employee_name || emp.name || '—';
}
function fmtClock(d) {
  const p = (n) => String(n).padStart(2, '0');
  return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
}

// ── PASS ────────────────────────────────────────────────────────────────────
function ymd(d) { const p = (n) => String(n).padStart(2, '0'); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; }
function passStatus(s) {
  return ({
    present: { l: 'มาทำงาน', cls: 'c-green' },
    in_only: { l: 'ยังไม่ออก', cls: 'c-amber' },
    late:    { l: 'มาสาย', cls: 'c-coral' },
    absent:  { l: 'ขาดงาน', cls: 'c-gray' },
    leave:   { l: 'ลา', cls: 'c-blue' },
    holiday: { l: 'วันหยุด', cls: 'c-gray' },
    off:     { l: 'วันหยุด', cls: 'c-gray' },
  }[s] || { l: s || '—', cls: 'c-gray' });
}

// Circular person avatar → /faces/<id>.jpg (or explicit photo), falls back to
// the round person-icon placeholder; click opens the profile modal.
function PassAvatar({ id, photo, size = 40 }) {
  const [err, setErr] = useModeState(false);
  const src = err ? '/img/avatar-person.svg' : (photo || (id ? `/faces/${id}.jpg` : '/img/avatar-person.svg'));
  return <img src={src} alt="" onError={() => setErr(true)}
    onClick={() => id && window.openProfile && window.openProfile(id)} title={id ? 'ดูโปรไฟล์' : ''}
    style={{ width: size, height: size, borderRadius: '50%', objectFit: 'cover', flex: 'none',
      cursor: id ? 'pointer' : 'default', border: '2px solid var(--surface)', boxShadow: '0 0 0 1px var(--line)' }} />;
}

function PassView({ clock, onLogout }) {
  const me = window.CURRENT_USER || {};
  const emps = window.EMPLOYEES || [];
  const emp = emps.find((e) => String(e.id) === String(me.employee_id)) || emps[0] || {};
  const [view, setView] = useModeState('home');   // home | history | leave
  const [att, setAtt] = useModeState([]);          // this week's attendance rows
  const [recent, setRecent] = useModeState(
    (window.RECENT_SCANS || []).filter((s) => String(s.employee_id || (s.employee && s.employee.id)) === String(emp.id)).slice(0, 6)
  );

  const now = new Date();
  const monday = new Date(now); monday.setDate(now.getDate() - ((now.getDay() + 6) % 7));
  const weekFrom = ymd(monday), weekTo = ymd(now), todayStr = ymd(now);

  const loadAtt = React.useCallback(() => {
    if (!emp.id) return;
    fetch(`/api/attendance/employee/${encodeURIComponent(emp.id)}?from=${weekFrom}&to=${weekTo}`, { credentials: 'include' })
      .then((r) => (r.ok ? r.json() : null)).then((d) => { if (d) setAtt(d.rows || []); }).catch(() => {});
  }, [emp.id, weekFrom, weekTo]);
  useModeEffect(() => { loadAtt(); }, [loadAtt]);
  useModeEffect(() => {
    if (!window.scanStream) return undefined;
    return window.scanStream.subscribe((scan) => {
      if (String(scan.employeeId) !== String(emp.id)) return;
      setRecent((prev) => [scan, ...prev].slice(0, 6));
      loadAtt();
    });
  }, [emp.id, loadAtt]);

  const todayRow = att.find((r) => r.date === todayStr) || {};
  const ci = (todayRow.first_scan || '').slice(11, 16) || '—';
  const co = (todayRow.last_scan || '').slice(11, 16) || '—';
  const checked = ci !== '—';
  const hrs = (m) => ((m || 0) / 60).toFixed(1);
  const weekMin = att.reduce((a, r) => a + (r.work_min || 0), 0);
  const otMin = att.reduce((a, r) => a + (r.ot_min || 0), 0);
  const st = passStatus(todayRow.status);

  const Tab = ({ id, label, icon }) => (
    <button onClick={() => setView(id)} style={{ flex: 1, textAlign: 'center', padding: '11px 6px', border: 'none', background: 'transparent', color: view === id ? 'var(--primary)' : 'var(--ink-4)', fontFamily: 'var(--font-body)', fontSize: 12.5, fontWeight: view === id ? 700 : 500, cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
      <span style={{ fontSize: 17, lineHeight: 1 }}>{icon}</span>{label}
    </button>
  );

  const shell = { background: 'var(--bg)', border: '1px solid var(--line)', borderRadius: 26 };

  return (
    <div className="fos-passwrap">
      <div className="fos-pass" style={shell}>
        {/* top bar (navy) */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '13px 18px', background: 'var(--navy)', color: '#fff', flexShrink: 0 }}>
          <span className="tnum" style={{ fontFamily: 'var(--font-display)', fontSize: 15, fontWeight: 700, letterSpacing: .3 }}>{clock}</span>
          <span style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <span style={{ fontSize: 12, color: 'rgba(255,255,255,.7)' }}>บัตรพนักงาน</span>
            {onLogout && <button onClick={onLogout} style={{ background: 'rgba(255,255,255,.14)', color: '#fff', border: '1px solid rgba(255,255,255,.28)', borderRadius: 'var(--r-pill)', fontFamily: 'inherit', fontSize: 12, fontWeight: 600, padding: '6px 12px', cursor: 'pointer' }}>ออก</button>}
          </span>
        </div>

        <div style={{ flex: 1, overflow: 'auto', background: 'var(--bg)', padding: 14 }}>
          {/* profile header card */}
          <div className="gv-card" style={{ padding: 18, marginBottom: 14 }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
              <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-5)' }}>บัตรพนักงาน / Employee</span>
              <span className={`gv-chip ${st.cls}`}>{st.l}</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>
              <PassAvatar id={emp.id} photo={emp.photo_url} size={104} />
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, marginTop: 12, lineHeight: 1.1 }}>{nameOf(emp)}</div>
              <div style={{ fontSize: 13.5, color: 'var(--ink-4)', marginTop: 3 }}>{emp.position || emp.role || me.role || '—'}</div>
              <div style={{ fontSize: 12, color: 'var(--ink-5)', marginTop: 4 }}>{emp.department_name || '—'} · รหัส {emp.id || '----'}</div>
            </div>
          </div>

          {view === 'home' && (
            <>
              {/* today check-in */}
              <div className="gv-card" style={{ padding: 18, marginBottom: 14 }}>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                  <div style={{ fontSize: 12.5, color: 'var(--ink-4)', fontWeight: 500 }}>เข้างานวันนี้</div>
                  <span className={`gv-chip ${checked ? 'c-green' : 'c-gray'}`}>{checked ? 'ลงเวลาแล้ว' : 'ยังไม่ลงเวลา'}</span>
                </div>
                <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 42, lineHeight: 1.05, marginTop: 8 }}>
                  {ci}{co !== '—' && <span style={{ fontSize: 20, color: 'var(--ink-4)' }}> → {co}</span>}
                </div>
                <div style={{ fontSize: 12.5, color: 'var(--ink-4)', marginTop: 6 }}>{todayRow.shift_name || 'ยังไม่ผูกกะ'}</div>
              </div>

              {/* mini stats */}
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10, marginBottom: 14 }}>
                {[['ชม.วันนี้', hrs(todayRow.work_min), 'var(--ink)'], ['ชม./สัปดาห์', hrs(weekMin), 'var(--ink)'], ['OT สัปดาห์', hrs(otMin), 'var(--coral-ink)']].map(([k, v, c]) => (
                  <div key={k} className="gv-card" style={{ padding: '13px 12px', textAlign: 'center' }}>
                    <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, color: c, lineHeight: 1 }}>{v}</div>
                    <div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 5 }}>{k}</div>
                  </div>
                ))}
              </div>

              {/* actions */}
              <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
                <button onClick={() => setView('leave')} className="gv-btn ok" style={{ flex: 1 }}>+ ขอลา</button>
                <button onClick={() => setView('correct')} className="gv-btn no" style={{ flex: 1 }}>⏱ แก้เวลา</button>
              </div>

              {/* recent */}
              <div className="gv-card">
                <div className="gv-card-h"><b>สแกนล่าสุด</b><span className="gv-chip c-gray">{recent.length}</span></div>
                <div className="gv-card-b" style={{ paddingTop: 6, paddingBottom: 8 }}>
                  {recent.length === 0 ? (
                    <div className="gv-empty">— ยังไม่มีบันทึก —</div>
                  ) : recent.map((r, i) => {
                    const out = r.type === 'out';
                    const tm = r.time instanceof Date ? fmtClock(r.time) : (r.time || '').slice(0, 8);
                    return (
                      <div key={i} className="gv-row">
                        <span className={`gv-chip ${out ? 'c-blue' : 'c-green'}`}>{out ? 'ออกงาน' : 'เข้างาน'}</span>
                        <span style={{ fontSize: 12.5, color: 'var(--ink-4)', flex: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{r.device_name || r.device || '—'}</span>
                        <span className="tnum" style={{ fontSize: 14, fontWeight: 700 }}>{tm}</span>
                      </div>
                    );
                  })}
                </div>
              </div>
            </>
          )}

          {view === 'history' && (
            <div className="gv-card">
              <div className="gv-card-h"><b>ประวัติลงเวลา · สัปดาห์นี้</b></div>
              <div className="gv-card-b" style={{ paddingTop: 6, paddingBottom: 8 }}>
                {att.length === 0 ? (
                  <div className="gv-empty">— ยังไม่มีข้อมูล —</div>
                ) : att.slice().reverse().map((r) => {
                  const s = passStatus(r.status);
                  return (
                    <div key={r.date} className="gv-row">
                      <span className="tnum" style={{ fontSize: 12.5, color: 'var(--ink-4)', width: 50 }}>{r.date.slice(5)}</span>
                      <span className="tnum" style={{ fontSize: 13, flex: 1 }}>{(r.first_scan || '').slice(11, 16) || '—'} → {(r.last_scan || '').slice(11, 16) || '—'}</span>
                      <span className="tnum" style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>{hrs(r.work_min)}ชม</span>
                      <span className={`gv-chip ${s.cls}`} style={{ marginLeft: 8 }}>{s.l}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {view === 'leave' && <PassLeave emp={emp} onDone={() => setView('home')}/>}
          {view === 'correct' && <PassCorrection emp={emp} onDone={() => { setView('home'); loadAtt(); }}/>}
        </div>

        {/* bottom tab bar (white, sky active) */}
        <div style={{ display: 'flex', borderTop: '1px solid var(--line)', background: 'var(--surface)', flexShrink: 0 }}>
          <Tab id="home" label="หน้าหลัก" icon="⌂"/>
          <Tab id="history" label="ประวัติ" icon="≣"/>
          <Tab id="leave" label="ขอลา" icon="＋"/>
        </div>
      </div>
    </div>
  );
}

// Working leave-request form on mobile → POST /api/leaves (+ shows balance).
function PassLeave({ emp, onDone }) {
  const types = window.LEAVE_TYPES || [];
  const today = ymd(new Date());
  const [type, setType] = useModeState((types[0] && types[0].code) || 'sick');
  const [from, setFrom] = useModeState(today);
  const [to, setTo] = useModeState(today);
  const [reason, setReason] = useModeState('');
  const [busy, setBusy] = useModeState(false);
  const [bal, setBal] = useModeState([]);

  useModeEffect(() => {
    if (!emp.id) return;
    fetch(`/api/leaves/balance?employee_id=${encodeURIComponent(emp.id)}`, { credentials: 'include' })
      .then((r) => (r.ok ? r.json() : null)).then((d) => { if (d) setBal(d.balance || []); }).catch(() => {});
  }, [emp.id]);

  const submit = async () => {
    if (to < from) { window.appToast && window.appToast('วันสิ้นสุดต้องไม่ก่อนวันเริ่ม', { tone: 'error' }); return; }
    setBusy(true);
    try {
      const r = await fetch('/api/leaves', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ employee_id: emp.id, leave_type: type, start_date: from, end_date: to, reason: reason.trim() }) });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'ส่งไม่สำเร็จ');
      window.appToast && window.appToast('ยื่นใบลาแล้ว — รออนุมัติ', { tone: 'success' });
      onDone();
    } catch (e) { window.appToast && window.appToast(e.message, { tone: 'error' }); }
    finally { setBusy(false); }
  };

  return (
    <div className="gv-card" style={{ padding: 18 }}>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 19 }}>ยื่นใบลา</div>
      {bal.length > 0 && (
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 12 }}>
          {bal.map((b) => (
            <span key={b.code} className="gv-chip c-gray">{b.name} {b.remaining != null ? `เหลือ ${b.remaining}` : `ใช้ ${b.used || 0}`}</span>
          ))}
        </div>
      )}
      <div className="gv-field" style={{ marginTop: 16 }}>
        <label>ประเภทการลา</label>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {types.map((t) => (
            <button key={t.code} type="button" onClick={() => setType(t.code)} className={`gv-chip ${type === t.code ? 'c-blue' : 'c-gray'}`} style={{ cursor: 'pointer', border: `1px solid ${type === t.code ? 'var(--primary)' : 'transparent'}`, fontSize: 13, padding: '7px 13px' }}>{t.name}</button>
          ))}
        </div>
      </div>
      <div style={{ display: 'flex', gap: 12 }}>
        <div className="gv-field" style={{ flex: 1 }}><label>วันเริ่ม</label><input type="date" value={from} onChange={(e) => setFrom(e.target.value)} className="gv-input"/></div>
        <div className="gv-field" style={{ flex: 1 }}><label>วันสิ้นสุด</label><input type="date" value={to} onChange={(e) => setTo(e.target.value)} className="gv-input"/></div>
      </div>
      <div className="gv-field"><label>เหตุผล</label><textarea value={reason} onChange={(e) => setReason(e.target.value)} rows={3} placeholder="(ไม่บังคับ)" className="gv-textarea" style={{ resize: 'none' }}/></div>
      <div style={{ display: 'flex', gap: 10, marginTop: 8 }}>
        <button onClick={onDone} disabled={busy} className="gv-btn no" style={{ flex: 1 }}>ยกเลิก</button>
        <button onClick={submit} disabled={busy} className="gv-btn ok" style={{ flex: 1.6 }}>{busy ? 'กำลังส่ง…' : 'ยื่นใบลา'}</button>
      </div>
    </div>
  );
}

// ── TERMINAL (kiosk) ─────────────────────────────────────────────────────────
function KioskView({ clock, dateStr, orgName, deviceLine }) {
  const [state, setState] = useModeState('idle');   // idle | scanning | success
  const [emp, setEmp] = useModeState(null);
  const timers = React.useRef([]);
  const clearTimers = () => { timers.current.forEach(clearTimeout); timers.current = []; };

  const showSuccess = (e) => {
    setEmp(e); setState('success');
    timers.current.push(setTimeout(() => { setState('idle'); setEmp(null); }, 4200));
  };

  // Real Hikvision scans arriving over the WebSocket drive the kiosk. A brief
  // "scanning" flash then the matched person — no simulation.
  useModeEffect(() => {
    if (!window.scanStream) return undefined;
    const unsub = window.scanStream.subscribe((scan) => {
      clearTimers();
      const e = scan.employee || (window.EMPLOYEES || []).find((x) => String(x.id) === String(scan.employeeId)) || { first_name: scan.employee_name || 'พนักงาน', id: scan.employeeId };
      setState('scanning');
      timers.current.push(setTimeout(() => showSuccess(e), 700));
    });
    return () => { unsub(); clearTimers(); };
  }, []);

  return (
    <div className="fos-kiosk">
      <div className="fos-kiosk-head">
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 40, height: 40, background: 'var(--fos-paper)', color: 'var(--fos-ink)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 20 }}>F</div>
          <div>
            <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 20, textTransform: 'uppercase', letterSpacing: -.5 }}>{orgName}</div>
            <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 10, letterSpacing: 2, color: '#9A9A9F' }}>FACE TERMINAL · ประตูหลัก</div>
          </div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 30, letterSpacing: 1, fontVariantNumeric: 'tabular-nums' }}>{clock}</div>
          <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 11, color: '#9A9A9F' }}>{dateStr}</div>
        </div>
      </div>

      <div className="fos-kiosk-main">
        {state === 'idle' && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', animation: 'osup .4s ease' }}>
            <div style={{ position: 'relative', width: 288, height: 340, border: '1.5px solid rgba(245,245,244,.4)', background: 'rgba(245,245,244,.04)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <svg width="130" height="130" viewBox="0 0 24 24" fill="none" stroke="rgba(245,245,244,.35)" strokeWidth="1"><circle cx="12" cy="9" r="4"/><path d="M5 20a7 7 0 0 1 14 0" strokeLinecap="round"/></svg>
              <div style={{ position: 'absolute', top: 10, left: 10, width: 32, height: 32, borderTop: '2.5px solid var(--fos-red)', borderLeft: '2.5px solid var(--fos-red)' }}/>
              <div style={{ position: 'absolute', top: 10, right: 10, width: 32, height: 32, borderTop: '2.5px solid var(--fos-red)', borderRight: '2.5px solid var(--fos-red)' }}/>
              <div style={{ position: 'absolute', bottom: 10, left: 10, width: 32, height: 32, borderBottom: '2.5px solid var(--fos-red)', borderLeft: '2.5px solid var(--fos-red)' }}/>
              <div style={{ position: 'absolute', bottom: 10, right: 10, width: 32, height: 32, borderBottom: '2.5px solid var(--fos-red)', borderRight: '2.5px solid var(--fos-red)' }}/>
              <div style={{ position: 'absolute', left: 0, right: 0, height: 2, background: 'var(--fos-red)', animation: 'osscan 2.8s ease-in-out infinite' }}/>
            </div>
            <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 30, marginTop: 30 }}>มองที่กล้องเพื่อลงเวลา</div>
            <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 13, letterSpacing: 1, color: '#9A9A9F', marginTop: 8 }}>LOOK AT THE CAMERA TO CLOCK IN / OUT</div>
            <div style={{ marginTop: 28, display: 'flex', alignItems: 'center', gap: 10, fontFamily: 'var(--fos-mono)', fontSize: 12, letterSpacing: 1, color: '#9A9A9F' }}>
              <span style={{ width: 8, height: 8, background: 'var(--fos-red)', borderRadius: '50%', animation: 'osblink 1.4s infinite' }}/>
              รอการสแกนจากเครื่อง · WAITING FOR DEVICE
            </div>
          </div>
        )}
        {state === 'scanning' && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', animation: 'osup .3s ease' }}>
            <div style={{ position: 'relative', width: 288, height: 340, border: '1.5px solid var(--fos-red)', background: 'rgba(229,38,28,.05)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <svg width="130" height="130" viewBox="0 0 24 24" fill="none" stroke="rgba(245,245,244,.6)" strokeWidth="1"><circle cx="12" cy="9" r="4"/><path d="M5 20a7 7 0 0 1 14 0" strokeLinecap="round"/></svg>
              <div className="fos-ring"/>
              <div style={{ position: 'absolute', left: 0, right: 0, height: 3, background: 'var(--fos-red)', animation: 'osscan 1s ease-in-out infinite' }}/>
            </div>
            <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 26, marginTop: 30, display: 'flex', alignItems: 'center', gap: 12 }}><span style={{ width: 12, height: 12, background: 'var(--fos-red)', animation: 'osblink 1s infinite' }}/>กำลังจดจำใบหน้า…</div>
            <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 12, letterSpacing: 1, color: '#9A9A9F', marginTop: 8 }}>HIKVISION MINMOE · PROCESSING</div>
          </div>
        )}
        {state === 'success' && emp && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', animation: 'osup .35s ease' }}>
            <div style={{ width: 130, height: 130, border: '1.5px solid var(--fos-paper)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 48 }}>{initialsOf(emp)}</div>
            <div style={{ marginTop: 22, padding: '9px 22px', background: 'var(--fos-green)', color: 'var(--fos-paper)', fontFamily: 'var(--fos-mono)', fontSize: 14, letterSpacing: 2, fontWeight: 600 }}>✓ ลงเวลาสำเร็จ · CONFIRMED</div>
            <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 34, marginTop: 22 }}>{nameOf(emp)}</div>
            <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 13, color: '#9A9A9F', marginTop: 6 }}>{(emp.position || emp.role || '')} · {emp.department_name || ''} · EMP//{emp.id}</div>
            <div style={{ fontFamily: 'var(--fos-display)', fontWeight: 700, fontSize: 58, marginTop: 18, letterSpacing: 2, fontVariantNumeric: 'tabular-nums' }}>{clock}</div>
            <div style={{ fontFamily: 'var(--fos-mono)', fontSize: 12, letterSpacing: 1, color: '#9A9A9F', marginTop: 8 }}>ขอให้เป็นวันที่ดี · HAVE A GREAT DAY</div>
          </div>
        )}
      </div>

      <div className="fos-kiosk-foot">
        <span style={{ width: 8, height: 8, background: 'var(--fos-red)', borderRadius: '50%', animation: 'osblink 1.4s infinite' }}/>
        SERVER CONNECTED · ระบบพร้อมใช้งาน · {deviceLine}
      </div>
    </div>
  );
}

// "ลืมสแกนเข้า/ออก" — employee submits a time-correction → HR/admin approves.
function PassCorrection({ emp, onDone }) {
  const today = ymd(new Date());
  const [date, setDate] = useModeState(today);
  const [punch, setPunch] = useModeState('in');
  const [time, setTime] = useModeState('08:00');
  const [reason, setReason] = useModeState('');
  const [busy, setBusy] = useModeState(false);

  const submit = async () => {
    if (!reason.trim()) { window.appToast && window.appToast('กรุณาระบุเหตุผล', { tone: 'error' }); return; }
    setBusy(true);
    try {
      const r = await fetch('/api/corrections', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ employee_id: emp.id, date, punch_type: punch, proposed_time: time, reason: reason.trim() }) });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'ส่งไม่สำเร็จ');
      window.appToast && window.appToast('ส่งคำขอแก้เวลาแล้ว — รออนุมัติ', { tone: 'success' });
      onDone();
    } catch (e) { window.appToast && window.appToast(e.message, { tone: 'error' }); }
    finally { setBusy(false); }
  };

  return (
    <div className="gv-card" style={{ padding: 18 }}>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 19 }}>ขอแก้เวลา</div>
      <div style={{ fontSize: 12.5, color: 'var(--ink-4)', marginTop: 4 }}>กรณีลืมสแกนเข้า/ออก — ส่งให้ HR/หัวหน้าอนุมัติ</div>
      <div className="gv-field" style={{ marginTop: 16 }}>
        <label>เข้า หรือ ออก</label>
        <div style={{ display: 'flex', gap: 8 }}>
          {[['in', 'เข้างาน'], ['out', 'ออกงาน']].map(([k, v]) => (
            <button key={k} type="button" onClick={() => setPunch(k)} className={punch === k ? 'gv-btn ok' : 'gv-btn no'} style={{ flex: 1 }}>{v}</button>
          ))}
        </div>
      </div>
      <div style={{ display: 'flex', gap: 12 }}>
        <div className="gv-field" style={{ flex: 1 }}><label>วันที่</label><input type="date" value={date} max={today} onChange={(e) => setDate(e.target.value)} className="gv-input"/></div>
        <div className="gv-field" style={{ flex: 1 }}><label>เวลา</label><input type="time" value={time} onChange={(e) => setTime(e.target.value)} className="gv-input"/></div>
      </div>
      <div className="gv-field"><label>เหตุผล *</label><textarea value={reason} onChange={(e) => setReason(e.target.value)} rows={3} placeholder="เช่น ลืมสแกนตอนเข้า / เครื่องค้าง" className="gv-textarea" style={{ resize: 'none' }}/></div>
      <div style={{ display: 'flex', gap: 10, marginTop: 8 }}>
        <button onClick={onDone} disabled={busy} className="gv-btn no" style={{ flex: 1 }}>ยกเลิก</button>
        <button onClick={submit} disabled={busy} className="gv-btn ok" style={{ flex: 1.6 }}>{busy ? 'กำลังส่ง…' : 'ส่งคำขอ'}</button>
      </div>
    </div>
  );
}

// ── ADMIN/HR mobile dashboard ────────────────────────────────────────────────
function AdminMobileView({ clock, dateStr, orgName, role, onLogout }) {
  const [sum, setSum] = useModeState(null);
  const [recent, setRecent] = useModeState((window.RECENT_SCANS || []).slice(0, 8));
  const [pend, setPend] = useModeState({ leave: 0, corr: 0 });

  const loadAll = React.useCallback(() => {
    fetch('/api/attendance/summary', { credentials: 'include' }).then((r) => r.ok ? r.json() : null).then((d) => d && setSum(d)).catch(() => {});
    Promise.all([
      fetch('/api/leaves?status=pending', { credentials: 'include' }).then((r) => r.ok ? r.json() : []).catch(() => []),
      fetch('/api/corrections?status=pending', { credentials: 'include' }).then((r) => r.ok ? r.json() : []).catch(() => []),
    ]).then(([lv, co]) => setPend({ leave: (lv || []).length, corr: (co || []).length }));
  }, []);
  useModeEffect(() => { loadAll(); }, [loadAll]);
  useModeEffect(() => {
    if (!window.scanStream) return undefined;
    return window.scanStream.subscribe((scan) => setRecent((prev) => [scan, ...prev].slice(0, 8)));
  }, []);

  const bs = sum?.by_status || {};
  const present = (bs.present || 0) + (bs.in_only || 0);
  const total = sum?.total ?? (window.EMPLOYEES?.length || 0);
  const sName = (s) => s.employee?.first_name ? `${s.employee.first_name} ${s.employee.last_name || ''}`.trim() : (s.first_name ? `${s.first_name} ${s.last_name || ''}`.trim() : (s.employee_name || 'ไม่รู้จัก'));
  const sTime = (s) => { const d = s.time instanceof Date ? s.time : (s.scan_time ? new Date(String(s.scan_time).replace(' ', 'T')) : null); if (!d) return '--:--'; const p = (n) => String(n).padStart(2, '0'); return `${p(d.getHours())}:${p(d.getMinutes())}`; };
  const sId = (s) => (s.employee && s.employee.id) || s.employeeId || s.employee_id || null;
  const sPhoto = (s) => s.photo_url || (s.employee && s.employee.photo_path ? `/faces/${s.employee.photo_path}` : null);

  const shell = { background: 'var(--bg)', border: '1px solid var(--line)', borderRadius: 26 };
  const miniStat = { flex: 1, background: 'var(--surface-2)', border: '1px solid var(--line)', borderRadius: 'var(--r-md)', padding: '12px 14px' };

  return (
    <div className="fos-passwrap">
      <div className="fos-pass" style={shell}>
        {/* top bar (navy) */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '13px 16px', background: 'var(--navy)', color: '#fff', flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <div style={{ width: 32, height: 32, borderRadius: 9, background: 'var(--primary)', color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 16 }}>{(orgName || 'F').slice(0, 1)}</div>
            <div>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 15, lineHeight: 1.1 }}>{orgName}</div>
              <div style={{ fontSize: 11, color: 'rgba(255,255,255,.7)', marginTop: 2 }}>{role || 'admin'} · <span className="tnum">{clock}</span></div>
            </div>
          </div>
          <button onClick={onLogout} style={{ background: 'rgba(255,255,255,.14)', color: '#fff', border: '1px solid rgba(255,255,255,.28)', borderRadius: 'var(--r-pill)', fontFamily: 'inherit', fontSize: 12, fontWeight: 600, padding: '6px 12px', cursor: 'pointer' }}>ออก</button>
        </div>

        <div style={{ flex: 1, overflow: 'auto', background: 'var(--bg)', padding: 14 }}>
          {/* presence */}
          <div className="gv-card" style={{ padding: 18, marginBottom: 14 }}>
            <div style={{ fontSize: 12, color: 'var(--ink-4)', fontWeight: 500 }}>ภาพรวมวันนี้ · {dateStr}</div>
            <div style={{ display: 'flex', alignItems: 'flex-end', gap: 12, marginTop: 6 }}>
              <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 60, lineHeight: .9, letterSpacing: -1, color: 'var(--navy)' }}>{present}</div>
              <div style={{ paddingBottom: 8 }}>
                <div style={{ fontSize: 14, fontWeight: 600 }}>เข้างานแล้ว</div>
                <div className="tnum" style={{ fontSize: 12, color: 'var(--ink-4)' }}>/ {total} คน</div>
              </div>
            </div>
          </div>

          {/* status mini cards */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10, marginBottom: 14 }}>
            {[['สาย', bs.late || 0, 'var(--coral-ink)'], ['ขาด', bs.absent || 0, 'var(--ink-4)'], ['ลา', bs.leave || 0, 'var(--primary-ink)']].map(([k, v, c]) => (
              <div key={k} className="gv-card" style={{ padding: '13px 12px', textAlign: 'center' }}>
                <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 24, color: c, lineHeight: 1 }}>{v}</div>
                <div style={{ fontSize: 11, color: 'var(--ink-4)', marginTop: 5 }}>{k}</div>
              </div>
            ))}
          </div>

          {/* pending approvals */}
          <div className="gv-card" style={{ padding: 16, marginBottom: 14 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink-4)', marginBottom: 10 }}>รออนุมัติ</div>
            <div style={{ display: 'flex', gap: 10 }}>
              <div style={miniStat}>
                <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 26, color: pend.leave ? 'var(--yellow-ink)' : 'var(--ink)' }}>{pend.leave}</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-4)', marginTop: 2 }}>ใบลา</div>
              </div>
              <div style={miniStat}>
                <div className="tnum" style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 26, color: pend.corr ? 'var(--yellow-ink)' : 'var(--ink)' }}>{pend.corr}</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-4)', marginTop: 2 }}>ขอแก้เวลา</div>
              </div>
            </div>
            {(pend.leave + pend.corr > 0) && (
              <a href="?view=desktop" className="gv-btn ok" style={{ display: 'block', textAlign: 'center', marginTop: 12, textDecoration: 'none' }}>เปิดเพื่ออนุมัติ →</a>
            )}
          </div>

          {/* ถ่ายรูปพนักงานด้วยกล้องมือถือ (admin/hr) */}
          {(role === 'admin' || role === 'hr') && <MobilePhotoCapture/>}

          {/* recent scans */}
          <div className="gv-card">
            <div className="gv-card-h"><b>สแกนล่าสุด</b><span className="gv-chip c-gray">{recent.length}</span></div>
            <div className="gv-card-b" style={{ paddingTop: 6, paddingBottom: 8 }}>
              {recent.length === 0 ? (
                <div className="gv-empty">— ยังไม่มีการสแกน —</div>
              ) : recent.map((s, i) => {
                const out = s.type === 'out';
                return (
                  <div key={i} className="gv-row">
                    <PassAvatar id={sId(s)} photo={sPhoto(s)} size={38} />
                    <span style={{ fontSize: 13.5, fontWeight: 600, flex: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{sName(s)}</span>
                    <span className={`gv-chip ${out ? 'c-blue' : 'c-green'}`}>{out ? 'ออก' : 'เข้า'}</span>
                    <span className="tnum" style={{ fontSize: 13, color: 'var(--ink-4)', minWidth: 44, textAlign: 'right' }}>{sTime(s)}</span>
                  </div>
                );
              })}
            </div>
          </div>
        </div>

        {/* footer → full console */}
        <a href="?view=desktop" style={{ flexShrink: 0, textAlign: 'center', padding: 14, borderTop: '1px solid var(--line)', background: 'var(--surface)', fontSize: 12.5, fontWeight: 600, color: 'var(--navy)', textDecoration: 'none' }}>⛶ เปิดโหมดจัดการเต็ม (Console)</a>
      </div>
    </div>
  );
}

// ── ถ่ายรูปพนักงานด้วยกล้องมือถือ (admin/hr) ────────────────────────────────
// ค้นชื่อ → แตะคน → กล้องเปิด → ย่อรูปในเครื่อง (≤1024px) → อัปโหลดเป็นรูปโปรไฟล์
// รูปนี้ใช้ส่งเข้าเครื่องสแกนต่อ (enroll-lan.js / ปุ่ม Sync)
function shrinkImage(file, max = 1024) {
  return new Promise((resolve) => {
    const done = (blob) => resolve(blob || file);
    const draw = (img, w, h) => {
      const s = Math.min(1, max / Math.max(w, h));
      const c = document.createElement('canvas'); c.width = Math.round(w * s); c.height = Math.round(h * s);
      c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
      c.toBlob(done, 'image/jpeg', 0.86);
    };
    if (window.createImageBitmap) {
      createImageBitmap(file, { imageOrientation: 'from-image' }).then((bm) => draw(bm, bm.width, bm.height)).catch(() => done(null));
    } else {
      const img = new Image(); img.onload = () => draw(img, img.naturalWidth, img.naturalHeight); img.onerror = () => done(null);
      img.src = URL.createObjectURL(file);
    }
  });
}

function MobilePhotoCapture() {
  const [q, setQ] = useModeState('');
  const [target, setTarget] = useModeState(null);     // พนักงานที่เลือก
  const [preview, setPreview] = useModeState(null);   // { blob, url }
  const [busy, setBusy] = useModeState(false);
  const [emps, setEmps] = useModeState(window.EMPLOYEES || []);
  const inputRef = React.useRef(null);

  const list = q.trim()
    ? emps.filter((e) => [e.id, e.first_name, e.last_name, e.department_name].filter(Boolean).some((v) => String(v).toLowerCase().includes(q.trim().toLowerCase()))).slice(0, 8)
    : [];
  const nameOf = (e) => `${e.title || ''}${e.first_name || ''} ${e.last_name || ''}`.trim();

  const pick = (e) => { setTarget(e); setPreview(null); setTimeout(() => inputRef.current && inputRef.current.click(), 50); };
  const onFile = async (ev) => {
    const f = ev.target.files && ev.target.files[0];
    ev.target.value = '';
    if (!f) return;
    const blob = await shrinkImage(f);
    setPreview({ blob, url: URL.createObjectURL(blob) });
  };
  const upload = async () => {
    if (!target || !preview) return;
    setBusy(true);
    try {
      const fd = new FormData(); fd.append('photo', preview.blob, `${target.id}.jpg`);
      const r = await fetch(`/api/employees/${encodeURIComponent(target.id)}/photo`, { method: 'POST', credentials: 'include', body: fd });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'อัปโหลดไม่สำเร็จ');
      window.appToast(`บันทึกรูป ${nameOf(target)} แล้ว`, { tone: 'success' });
      await window.refreshData(); setEmps(window.EMPLOYEES || []);
      setTarget(null); setPreview(null); setQ('');
    } catch (e) { window.appToast(e.message, { tone: 'error' }); }
    finally { setBusy(false); }
  };

  return (
    <div className="gv-card" style={{ marginBottom: 14 }}>
      <div className="gv-card-h"><b>📷 ถ่ายรูปพนักงาน</b><span style={{ fontSize: 11.5, color: 'var(--ink-5)' }}>ใช้กล้องมือถือ</span></div>
      <div className="gv-card-b" style={{ paddingTop: 10 }}>
        <input ref={inputRef} type="file" accept="image/*" capture="user" style={{ display: 'none' }} onChange={onFile}/>
        {!target && (
          <>
            <input className="gv-input" value={q} onChange={(e) => setQ(e.target.value)} placeholder="พิมพ์ชื่อ หรือ รหัสพนักงาน" style={{ fontSize: 16 }}/>
            {list.length > 0 && (
              <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 4 }}>
                {list.map((e) => (
                  <button key={e.id} onClick={() => pick(e)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', border: '1px solid var(--line)', borderRadius: 12, background: 'var(--surface)', textAlign: 'left', fontFamily: 'inherit', cursor: 'pointer' }}>
                    <PassAvatar id={e.id} photo={e.photo_url} size={36}/>
                    <span style={{ flex: 1 }}>
                      <span style={{ display: 'block', fontSize: 13.5, fontWeight: 600 }}>{nameOf(e)}</span>
                      <span style={{ display: 'block', fontSize: 11.5, color: 'var(--ink-5)' }}>{e.id} · {e.department_name || '—'}{e.photo_url ? '' : ' · ยังไม่มีรูป'}</span>
                    </span>
                    <span className="gv-chip c-blue">ถ่าย</span>
                  </button>
                ))}
              </div>
            )}
            {q.trim() && list.length === 0 && <div style={{ fontSize: 12.5, color: 'var(--ink-5)', marginTop: 8 }}>ไม่พบ "{q}"</div>}
          </>
        )}
        {target && (
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
            <div style={{ fontSize: 13.5, fontWeight: 600 }}>{nameOf(target)} <span style={{ color: 'var(--ink-5)', fontWeight: 400 }}>· {target.id}</span></div>
            {preview
              ? <img src={preview.url} alt="" style={{ width: 180, height: 180, objectFit: 'cover', borderRadius: 20, border: '3px solid var(--primary)' }}/>
              : <div style={{ fontSize: 12.5, color: 'var(--ink-5)' }}>กำลังเปิดกล้อง… ถ้าไม่เปิดให้กด "ถ่ายใหม่"</div>}
            <div style={{ fontSize: 11.5, color: 'var(--ink-5)', textAlign: 'center' }}>หน้าตรง · แสงสว่าง · ไม่ใส่หมวก/แว่นดำ · ให้หน้าเต็มกรอบ</div>
            <div style={{ display: 'flex', gap: 8, width: '100%' }}>
              <button className="gv-btn no" style={{ flex: 1, justifyContent: 'center' }} onClick={() => { setTarget(null); setPreview(null); }} disabled={busy}>ยกเลิก</button>
              <button className="gv-btn no" style={{ flex: 1, justifyContent: 'center' }} onClick={() => inputRef.current && inputRef.current.click()} disabled={busy}>ถ่ายใหม่</button>
              <button className="gv-btn ok" style={{ flex: 1.4, justifyContent: 'center' }} onClick={upload} disabled={busy || !preview}>{busy ? 'กำลังบันทึก…' : 'บันทึกรูป'}</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

window.PassView = PassView;
window.KioskView = KioskView;
window.AdminMobileView = AdminMobileView;
