/* global React, window, Icon, Avatar */
const { useState: useEmpState, useEffect: useEmpEffect, useMemo: useEmpMemo } = React;

// พนักงาน — roster CRUD + face enrollment to Hikvision devices.
function EmployeePage({ role }) {
  const [emps, setEmps] = useEmpState(window.EMPLOYEES || []);
  const [search, setSearch] = useEmpState('');
  const [deptFilter, setDeptFilter] = useEmpState('all');
  const [editing, setEditing] = useEmpState(null);
  const [syncingId, setSyncingId] = useEmpState(null);
  const [importing, setImporting] = useEmpState(false);
  const [accounts, setAccounts] = useEmpState(null);   // ผลจากสร้างบัญชีมือถือทั้งหมด
  const canEdit = role === 'admin' || role === 'hr';

  const reload = async () => {
    await window.refreshData();
    setEmps(window.EMPLOYEES || []);
  };
  useEmpEffect(() => { reload(); }, []);

  const filtered = useEmpMemo(() => {
    const q = search.trim().toLowerCase();
    return emps.filter((e) => {
      if (deptFilter !== 'all' && String(e.department_id) !== deptFilter) return false;
      if (!q) return true;
      return [e.id, e.first_name, e.last_name, e.email, e.department_name]
        .filter(Boolean).some((v) => String(v).toLowerCase().includes(q));
    });
  }, [emps, search, deptFilter]);

  const syncOne = async (emp) => {
    setSyncingId(emp.id);
    try {
      const r = await fetch(`/api/employees/${encodeURIComponent(emp.id)}/sync`, { method: 'POST', credentials: 'include' });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || `error ${r.status}`);
      window.appToast(`Sync ${emp.first_name}: ${d.synced}/${d.online} เครื่อง` + (d.offline ? ` · ข้าม ${d.offline} offline` : ''), { tone: d.synced ? 'success' : 'error' });
    } catch (e) {
      window.appToast('Sync ไม่สำเร็จ: ' + e.message, { tone: 'error' });
    } finally { setSyncingId(null); }
  };

  // Generate a mobile login account for this employee (role=employee, linked by employee_id).
  const makeLogin = async (emp) => {
    const username = String(emp.id);
    const pwd = 'gb' + Math.random().toString(36).slice(2, 8);
    const go = await window.appConfirm({ title: 'สร้างบัญชีเข้าระบบ', message: `สร้าง login ให้ ${emp.first_name || ''} ${emp.last_name || ''} เพื่อใช้บนมือถือ (ดูบัตร · ลงเวลา · ขอลา · ขอแก้เวลา)?`, confirmText: 'สร้างบัญชี' });
    if (!go) return;
    const r = await fetch('/api/users', {
      method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password: pwd, display_name: `${emp.first_name || ''} ${emp.last_name || ''}`.trim(), role: 'employee', employee_id: emp.id, department_id: emp.department_id || null }),
    });
    const d = await r.json().catch(() => ({}));
    if (!r.ok) { window.appToast(d.error || 'สร้างไม่สำเร็จ (อาจมีบัญชีนี้แล้ว)', { tone: 'error' }); return; }
    await window.appConfirm({ title: 'สร้างบัญชีสำเร็จ ✓', message: `ให้พนักงานล็อกอินบนมือถือด้วย — Username: ${username} · Password: ${pwd}  (จดไว้ แสดงครั้งเดียว)`, confirmText: 'รับทราบ' });
  };

  return (
    <div data-screen-label="Employee">
      <div className="page-head">
        <div>
          <h1>{window.T.staff}</h1>
          <div className="sub">จัดการรายชื่อ · ผูก{window.T.dept}/กะ · Sync ใบหน้าไปเครื่องสแกน {(window.DEVICES || []).length} เครื่อง</div>
        </div>
        <div className="row" style={{gap: 8}}>
          {canEdit && (
            <button className="btn btn-soft btn-sm" onClick={async () => {
              const ok = await window.appConfirm({ title: 'Sync ทุกคนไปทุกเครื่อง?', message: 'อาจใช้เวลาหลายนาที', confirmText: 'Sync' });
              if (!ok) return;
              window.appToast('กำลัง sync ทั้งหมด…');
              const r = await fetch('/api/employees/sync-all', { method: 'POST', credentials: 'include' });
              const d = await r.json().catch(() => ({}));
              window.appToast(`Sync เสร็จ: ${d.synced}/${d.total} คน`, { tone: 'success' });
            }}><Icon name="refresh" size={13}/>Sync ทั้งหมด</button>
          )}
          {canEdit && (
            <button className="btn btn-soft btn-sm" title="สร้างบัญชีล็อกอินมือถือให้พนักงานทุกคนที่ยังไม่มี" onClick={async () => {
              const ok = await window.appConfirm({ title: 'สร้างบัญชีมือถือให้พนักงานทุกคน?', message: 'สร้างเฉพาะคนที่ยังไม่มีบัญชี — username = รหัสพนักงาน, รหัสผ่านสุ่ม 6 หลัก (แสดงครั้งเดียว พิมพ์/คัดลอกเก็บไว้)', confirmText: 'สร้าง' });
              if (!ok) return;
              const r = await fetch('/api/employees/accounts/bulk', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: '{}' });
              const d = await r.json().catch(() => ({}));
              if (!r.ok) { window.appToast(d.error || 'สร้างไม่สำเร็จ', { tone: 'error' }); return; }
              setAccounts(d);
            }}><Icon name="badge" size={13}/>บัญชีมือถือ</button>
          )}
          {canEdit && (
            <button className="btn btn-soft btn-sm" onClick={() => setImporting(true)}>
              <Icon name="upload" size={13}/>นำเข้า Excel
            </button>
          )}
          {canEdit && (
            <button className="btn btn-coral btn-sm" onClick={() => setEditing({})}>
              <Icon name="plus" size={13}/>เพิ่ม{window.T.staff}
            </button>
          )}
        </div>
      </div>
      {importing && <ImportExcelModal onClose={() => setImporting(false)} onDone={async () => { setImporting(false); await reload(); }}/>}
      {accounts && <AccountsResultModal data={accounts} onClose={() => setAccounts(null)}/>}

      {/* Filter bar */}
      <div className="row" style={{gap: 10, marginBottom: 14, flexWrap: 'wrap'}}>
        <div className="topbar-search" style={{flex: 1, minWidth: 220, marginLeft: 0}}>
          <Icon name="search" size={16}/>
          <input value={search} onChange={(e) => setSearch(e.target.value)} placeholder="ค้นหา ชื่อ / รหัส / อีเมล"/>
        </div>
        <select className="input" value={deptFilter} onChange={(e) => setDeptFilter(e.target.value)} style={{maxWidth: 220}}>
          <option value="all">ทุก{window.T.dept}</option>
          {(window.DEPARTMENTS || []).map((d) => <option key={d.id} value={String(d.id)}>{d.name}</option>)}
        </select>
      </div>

      <div className="card bare">
        <div className="scroll-thin" style={{maxHeight: 'calc(100vh - 280px)', overflowY: 'auto'}}>
          <table className="tbl">
            <thead>
              <tr><th>{window.T.staff}</th><th>{window.T.dept}</th><th>กะ</th><th>สถานะ</th><th></th></tr>
            </thead>
            <tbody>
              {filtered.map((e) => {
                const person = { name: `${e.first_name} ${e.last_name || ''}`.trim(), photo_url: e.photo_url, color: e.department_color || 'coral' };
                return (
                  <tr key={e.id}>
                    <td>
                      <div className="row" style={{gap: 10, cursor: 'pointer'}} onClick={() => window.openProfile && window.openProfile(e.id)} title="ดูโปรไฟล์">
                        <Avatar person={person}/>
                        <div>
                          <div style={{fontWeight: 600, fontSize: 13.5}}>{person.name}</div>
                          <div className="muted" style={{fontSize: 11.5}}>{e.id}{e.email ? ` · ${e.email}` : ''}</div>
                        </div>
                      </div>
                    </td>
                    <td>{e.department_name ? <span className={`chip ${e.department_color || 'coral'}`} style={{padding: '2px 9px', fontSize: 11}}>{e.department_name}</span> : <span className="muted">—</span>}</td>
                    <td className="muted" style={{fontSize: 12.5}}>{shiftName(e.shift_id) || <span style={{opacity: 0.5}}>ตาม{window.T.dept}</span>}</td>
                    <td>
                      {e.photo_url
                        ? <span className="chip mint" style={{padding: '1px 8px', fontSize: 11}}><Icon name="check" size={10}/>มีรูป</span>
                        : <span className="chip" style={{padding: '1px 8px', fontSize: 11, background: 'var(--surface-2)'}}>ยังไม่มีรูป</span>}
                    </td>
                    <td style={{textAlign: 'right'}}>
                      {canEdit && (
                        <div className="row" style={{gap: 4, justifyContent: 'flex-end'}}>
                          <button className="btn btn-soft btn-sm" disabled={syncingId === e.id || !e.photo_url}
                            onClick={() => syncOne(e)} title={e.photo_url ? 'Sync ใบหน้าไปเครื่อง' : 'ต้องมีรูปก่อน'}>
                            <Icon name="refresh" size={12}/>{syncingId === e.id ? '…' : 'Sync'}
                          </button>
                          <button className="btn btn-soft btn-sm" title="สร้างบัญชีเข้าระบบสำหรับพนักงานนี้" onClick={() => makeLogin(e)}><Icon name="badge" size={12}/>Login</button>
                          <button className="tb-icon-btn" style={{width: 30, height: 30}} onClick={() => setEditing(e)}><Icon name="edit" size={14}/></button>
                        </div>
                      )}
                    </td>
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan={5} style={{padding: 32, textAlign: 'center', color: 'var(--ink-4)'}}>ไม่พบพนักงาน</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </div>

      {editing && <EmpModal emp={editing} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); reload(); }} canDelete={role === 'admin'}/>}
    </div>
  );
}

function shiftName(id) {
  if (!id) return null;
  const s = (window.SHIFTS || []).find((x) => x.id === id);
  return s ? s.name : null;
}

function EmpModal({ emp, onClose, onSaved, canDelete }) {
  const isNew = !emp.id;
  const [id, setId] = useEmpState(emp.id || '');
  const [title, setTitle] = useEmpState(emp.title || '');
  const [first, setFirst] = useEmpState(emp.first_name || '');
  const [last, setLast] = useEmpState(emp.last_name || '');
  const [email, setEmail] = useEmpState(emp.email || '');
  const [phone, setPhone] = useEmpState(emp.phone || '');
  const [deptId, setDeptId] = useEmpState(emp.department_id || '');
  const [shiftId, setShiftId] = useEmpState(emp.shift_id || '');
  const [hireDate, setHireDate] = useEmpState(emp.hire_date || '');
  const [baseSalary, setBaseSalary] = useEmpState(emp.base_salary || '');
  const [payType, setPayType] = useEmpState(emp.pay_type || 'monthly');
  const [ssoEnabled, setSsoEnabled] = useEmpState(emp.sso_enabled === 0 ? false : true);
  const [photoFile, setPhotoFile] = useEmpState(null);
  const [busy, setBusy] = useEmpState(false);
  const [err, setErr] = useEmpState('');

  const save = async () => {
    if (!id.trim() || !first.trim()) { setErr('ต้องมีรหัสพนักงานและชื่อ'); return; }
    setBusy(true); setErr('');
    try {
      const fd = new FormData();
      fd.append('id', id.trim());
      fd.append('title', title);
      fd.append('first_name', first.trim());
      fd.append('last_name', last.trim());
      fd.append('email', email.trim());
      fd.append('phone', phone.trim());
      if (deptId) fd.append('department_id', deptId);
      if (shiftId) fd.append('shift_id', shiftId);
      if (hireDate) fd.append('hire_date', hireDate);
      fd.append('base_salary', baseSalary || 0);
      fd.append('pay_type', payType);
      fd.append('sso_enabled', ssoEnabled ? 1 : 0);
      if (photoFile) fd.append('photo', photoFile);
      const url = isNew ? '/api/employees' : `/api/employees/${encodeURIComponent(emp.id)}`;
      const r = await fetch(url, { method: isNew ? 'POST' : 'PUT', credentials: 'include', body: fd });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || `error ${r.status}`);
      window.appToast(isNew ? 'เพิ่มพนักงานแล้ว' : 'บันทึกแล้ว', { tone: 'success' });
      onSaved();
    } catch (e) { setErr(e.message); } finally { setBusy(false); }
  };

  const del = async () => {
    const ok = await window.appConfirm({ title: `ลบ "${first} ${last}"?`, message: 'ลบข้อมูล + รูปออกจากระบบ (ประวัติการสแกนยังอยู่)', danger: true, confirmText: 'ลบ' });
    if (!ok) return;
    setBusy(true);
    try {
      const r = await fetch(`/api/employees/${encodeURIComponent(emp.id)}`, { method: 'DELETE', credentials: 'include' });
      if (!r.ok) throw new Error('ลบไม่สำเร็จ');
      window.appToast('ลบแล้ว', { tone: 'success' });
      onSaved();
    } catch (e) { setErr(e.message); setBusy(false); }
  };

  return (
    <window.ModalShell title={isNew ? 'เพิ่มพนักงาน' : 'แก้ไขพนักงาน'} onClose={onClose} width={580}>
      <div className="col" style={{gap: 14}}>
        <div className="row" style={{gap: 12}}>
          <div className="field" style={{width: 120}}>
            <label className="field-label">รหัส *</label>
            <input className="input" value={id} onChange={(e) => setId(e.target.value)} disabled={!isNew} placeholder="EMP001"/>
          </div>
          <div className="field" style={{width: 90}}>
            <label className="field-label">คำนำหน้า</label>
            <input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="นาย"/>
          </div>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">ชื่อ *</label>
            <input className="input" value={first} onChange={(e) => setFirst(e.target.value)}/>
          </div>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">นามสกุล</label>
            <input className="input" value={last} onChange={(e) => setLast(e.target.value)}/>
          </div>
        </div>
        <div className="row" style={{gap: 12}}>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">อีเมล</label>
            <input className="input" value={email} onChange={(e) => setEmail(e.target.value)}/>
          </div>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">เบอร์โทร</label>
            <input className="input" value={phone} onChange={(e) => setPhone(e.target.value)}/>
          </div>
        </div>
        <div className="row" style={{gap: 12}}>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">{window.T.dept}</label>
            <select className="input" value={deptId} onChange={(e) => setDeptId(e.target.value)}>
              <option value="">— ไม่ผูก{window.T.dept} —</option>
              {(window.DEPARTMENTS || []).map((d) => <option key={d.id} value={d.id}>{d.name}</option>)}
            </select>
          </div>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">กะ (ถ้าต่างจาก{window.T.dept})</label>
            <select className="input" value={shiftId} onChange={(e) => setShiftId(e.target.value)}>
              <option value="">— ตาม{window.T.dept} —</option>
              {(window.SHIFTS || []).map((s) => <option key={s.id} value={s.id}>{s.name}</option>)}
            </select>
          </div>
        </div>
        <div className="row" style={{gap: 12}}>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">วันเริ่มงาน</label>
            <input className="input" type="date" value={hireDate} onChange={(e) => setHireDate(e.target.value)}/>
          </div>
          <div className="field" style={{flex: 1}}>
            <label className="field-label">รูปใบหน้า {emp.photo_url && '(มีแล้ว)'}</label>
            <input className="input" type="file" accept="image/jpeg,image/png" onChange={(e) => setPhotoFile(e.target.files?.[0] || null)}/>
          </div>
        </div>
        {/* Pay profile — used by the payroll module */}
        <div style={{borderTop: '1px solid var(--line)', paddingTop: 12}}>
          <div className="label-sm" style={{marginBottom: 8}}>ข้อมูลเงินเดือน</div>
          <div className="row" style={{gap: 12}}>
            <div className="field" style={{flex: 1}}>
              <label className="field-label">ประเภทการจ่าย</label>
              <select className="input" value={payType} onChange={(e) => setPayType(e.target.value)}>
                <option value="monthly">รายเดือน</option>
                <option value="daily">รายวัน</option>
                <option value="hourly">รายชั่วโมง</option>
              </select>
            </div>
            <div className="field" style={{flex: 1}}>
              <label className="field-label">
                {payType === 'monthly' ? 'เงินเดือน (บาท)' : payType === 'daily' ? 'ค่าแรง/วัน (บาท)' : 'ค่าแรง/ชม. (บาท)'}
              </label>
              <input className="input" type="number" value={baseSalary} onChange={(e) => setBaseSalary(e.target.value)} placeholder="0"/>
            </div>
            <div className="field" style={{width: 140}}>
              <label className="field-label">ประกันสังคม</label>
              <label className="row" style={{gap: 8, padding: '9px 0', cursor: 'pointer'}}>
                <input type="checkbox" checked={ssoEnabled} onChange={(e) => setSsoEnabled(e.target.checked)} style={{width: 16, height: 16}}/>
                <span style={{fontSize: 13}}>หัก ปกส.</span>
              </label>
            </div>
          </div>
        </div>
        <div style={{padding: 12, borderRadius: 10, background: 'var(--surface-2)', fontSize: 12, color: 'var(--ink-3)'}}>
          <Icon name="refresh" size={12} style={{verticalAlign: 'middle', marginRight: 4}}/>
          หลังบันทึก กดปุ่ม "Sync" ในตารางเพื่อส่งใบหน้าขึ้นเครื่องสแกน
        </div>
        {err && <div style={{padding: '10px 14px', borderRadius: 10, background: 'rgba(220,38,38,0.08)', color: '#DC2626', fontSize: 12.5, fontWeight: 600}}>{err}</div>}
        <div className="row" style={{justifyContent: 'space-between', marginTop: 4}}>
          <div>{!isNew && canDelete && <button className="btn btn-ghost" style={{color: 'var(--red, #DC2626)'}} onClick={del} disabled={busy}><Icon name="trash" size={13}/>ลบ</button>}</div>
          <div className="row" style={{gap: 8}}>
            <button className="btn btn-ghost" onClick={onClose} disabled={busy}>ยกเลิก</button>
            <button className="btn btn-coral" onClick={save} disabled={busy}>{busy ? 'กำลังบันทึก…' : 'บันทึก'}</button>
          </div>
        </div>
      </div>
    </window.ModalShell>
  );
}

// ── นำเข้าจาก Excel: เลือกไฟล์ → ตรวจก่อน (dry run) → ยืนยันบันทึก ───────────
function ImportExcelModal({ onClose, onDone }) {
  const [file, setFile] = useEmpState(null);
  const [preview, setPreview] = useEmpState(null);   // ผลจาก ?dry=1
  const [busy, setBusy] = useEmpState(false);
  const [err, setErr] = useEmpState('');
  const [result, setResult] = useEmpState(null);

  const pick = async (f) => {
    setFile(f); setPreview(null); setResult(null); setErr('');
    if (!f) return;
    setBusy(true);
    try {
      const fd = new FormData(); fd.append('file', f);
      const r = await fetch('/api/employees/import?dry=1', { method: 'POST', credentials: 'include', body: fd });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'อ่านไฟล์ไม่สำเร็จ');
      setPreview(d);
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  };

  const commit = async () => {
    if (!file || !preview || !preview.valid) return;
    setBusy(true); setErr('');
    try {
      const fd = new FormData(); fd.append('file', file);
      const r = await fetch('/api/employees/import', { method: 'POST', credentials: 'include', body: fd });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'นำเข้าไม่สำเร็จ');
      setResult(d);
      window.appToast(`นำเข้าแล้ว ${d.imported} คน`, { tone: 'success' });
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  };

  const bad = preview ? preview.rows.filter((x) => x.issues.length) : [];
  const good = preview ? preview.rows.filter((x) => !x.issues.length) : [];

  return (
    <window.ModalShell title="นำเข้าพนักงานจาก Excel" onClose={onClose} width={760}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div className="row" style={{ gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
          <a className="btn btn-soft btn-sm" href="/api/employees/import/template" download>
            <Icon name="download" size={13}/>ไฟล์ต้นแบบ (.xlsx)
          </a>
          <label className="btn btn-coral btn-sm" style={{ cursor: 'pointer' }}>
            <Icon name="upload" size={13}/>{file ? 'เลือกไฟล์อื่น' : 'เลือกไฟล์ Excel'}
            <input type="file" accept=".xlsx,.xls,.csv" style={{ display: 'none' }}
                   onChange={(e) => pick(e.target.files && e.target.files[0])}/>
          </label>
          {file && <span style={{ fontSize: 12.5, color: 'var(--ink-5)' }}>{file.name}</span>}
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--ink-5)', lineHeight: 1.6 }}>
          แถวแรกต้องเป็นหัวตาราง ต้องมีคอลัมน์ <b>รหัสพนักงาน</b> และ <b>ชื่อ</b> — คอลัมน์อื่น (นามสกุล กอง ตำแหน่ง กะงาน เบอร์โทร วันเริ่มงาน เงินเดือน) ใส่ได้ตามต้องการ
          รหัสที่มีอยู่แล้วจะถูกอัปเดต ไม่สร้างซ้ำ
        </div>

        {busy && <div style={{ fontSize: 13 }}>กำลังอ่านไฟล์…</div>}
        {err && <div style={{ padding: '10px 14px', borderRadius: 10, background: 'var(--coral-soft)', color: 'var(--coral-ink)', fontSize: 13 }}>{err}</div>}

        {preview && !result && (
          <>
            <div className="row" style={{ gap: 8, flexWrap: 'wrap' }}>
              <span className="gv-chip c-blue">ทั้งหมด {preview.total}</span>
              <span className="gv-chip c-green">เพิ่มใหม่ {preview.new}</span>
              <span className="gv-chip c-violet">อัปเดต {preview.update}</span>
              {preview.invalid > 0 && <span className="gv-chip c-coral">มีปัญหา {preview.invalid} (จะข้าม)</span>}
            </div>
            <div style={{ maxHeight: 300, overflow: 'auto', border: '1px solid var(--line)', borderRadius: 10 }}>
              <table className="gv-tbl" style={{ fontSize: 12.5 }}>
                <thead><tr><th>แถว</th><th>รหัส</th><th>ชื่อ-นามสกุล</th><th>กอง</th><th>ตำแหน่ง</th><th>สถานะ</th></tr></thead>
                <tbody>
                  {[...bad, ...good].slice(0, 300).map((r) => (
                    <tr key={r.row} style={r.issues.length ? { background: 'var(--coral-soft)' } : null}>
                      <td className="tnum">{r.row}</td>
                      <td className="tnum">{r.id || '—'}</td>
                      <td>{[r.title, r.first_name, r.last_name].filter(Boolean).join(' ')}</td>
                      <td>{r.department_name || '—'}</td>
                      <td>{r.position || '—'}</td>
                      <td>{r.issues.length
                        ? <span style={{ color: 'var(--coral-ink)' }}>{r.issues.join(' · ')}</span>
                        : <span className={`gv-chip ${r.exists ? 'c-violet' : 'c-green'}`}>{r.exists ? 'อัปเดต' : 'ใหม่'}</span>}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <div className="row" style={{ justifyContent: 'flex-end', gap: 8 }}>
              <button className="btn btn-soft btn-sm" onClick={onClose}>ยกเลิก</button>
              <button className="btn btn-coral btn-sm" disabled={busy || !preview.valid} onClick={commit}>
                บันทึก {preview.valid} คน{preview.invalid ? ` (ข้าม ${preview.invalid})` : ''}
              </button>
            </div>
          </>
        )}

        {result && (
          <>
            <div style={{ padding: '12px 14px', borderRadius: 10, background: 'var(--mint-soft)', color: 'var(--mint-ink)', fontSize: 13.5 }}>
              นำเข้าเรียบร้อย <b>{result.imported}</b> คน (ใหม่ {result.new} · อัปเดต {result.update})
              {result.skipped && result.skipped.length ? ` · ข้าม ${result.skipped.length} แถวที่มีปัญหา` : ''}
              {result.errors && result.errors.length ? ` · บันทึกไม่ได้ ${result.errors.length} แถว` : ''}
            </div>
            {result.errors && result.errors.length > 0 && (
              <div style={{ fontSize: 12.5, color: 'var(--coral-ink)' }}>
                {result.errors.map((e) => <div key={e.row}>แถว {e.row} ({e.id}): {e.error}</div>)}
              </div>
            )}
            <div className="row" style={{ justifyContent: 'flex-end' }}>
              <button className="btn btn-coral btn-sm" onClick={onDone}>เสร็จสิ้น</button>
            </div>
          </>
        )}
      </div>
    </window.ModalShell>
  );
}

// ผลการสร้างบัญชีมือถือ — ตารางชื่อผู้ใช้/รหัสผ่าน (แสดงครั้งเดียว) + คัดลอก/ดาวน์โหลด CSV
function AccountsResultModal({ data, onClose }) {
  const rows = data.created || [];
  const url = (window.SETTINGS && window.SETTINGS.public_base_url) || location.origin;
  const text = ['รหัสพนักงาน,ชื่อ,กอง,ชื่อผู้ใช้,รหัสผ่าน,เข้าใช้ที่', ...rows.map((r) => [r.id, r.name, r.department, r.username, r.password, url].join(','))].join('\n');
  const copy = async () => { try { await navigator.clipboard.writeText(text); window.appToast('คัดลอกแล้ว', { tone: 'success' }); } catch (_) { window.appToast('คัดลอกไม่ได้ ให้เลือกข้อความเอง', { tone: 'error' }); } };
  const download = () => {
    const blob = new Blob(['﻿' + text], { type: 'text/csv;charset=utf-8' });   // BOM ให้ Excel อ่านไทยถูก
    const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'บัญชีมือถือพนักงาน.csv'; a.click();
  };
  return (
    <window.ModalShell title="บัญชีมือถือของพนักงาน" onClose={onClose} width={720}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ padding: '10px 14px', borderRadius: 10, background: 'var(--mint-soft)', color: 'var(--mint-ink)', fontSize: 13.5 }}>
          สร้างใหม่ <b>{rows.length}</b> บัญชี{data.skipped && data.skipped.length ? ` · มีอยู่แล้ว ${data.skipped.length}` : ''}{data.failed && data.failed.length ? ` · ไม่สำเร็จ ${data.failed.length}` : ''}
          <div style={{ fontSize: 12, marginTop: 4 }}>รหัสผ่านแสดง<b>ครั้งเดียว</b> — คัดลอกหรือดาวน์โหลดเก็บไว้ก่อนปิด · พนักงานเข้าที่ <b>{url}</b> บนมือถือ แล้วกด "เพิ่มไปยังหน้าจอหลัก" จะได้เป็นแอป</div>
        </div>
        {rows.length > 0 && (
          <div style={{ maxHeight: 320, overflow: 'auto', border: '1px solid var(--line)', borderRadius: 10 }}>
            <table className="gv-tbl" style={{ fontSize: 13 }}>
              <thead><tr><th>รหัส</th><th>ชื่อ</th><th>กอง</th><th>ชื่อผู้ใช้</th><th>รหัสผ่าน</th></tr></thead>
              <tbody>{rows.map((r) => (
                <tr key={r.id}><td className="tnum">{r.id}</td><td>{r.name}</td><td>{r.department || '—'}</td>
                  <td className="tnum" style={{ fontFamily: 'var(--font-mono)' }}>{r.username}</td>
                  <td className="tnum" style={{ fontFamily: 'var(--font-mono)', fontWeight: 700 }}>{r.password}</td></tr>
              ))}</tbody>
            </table>
          </div>
        )}
        {data.failed && data.failed.length > 0 && <div style={{ fontSize: 12.5, color: 'var(--coral-ink)' }}>{data.failed.map((x) => <div key={x.id}>{x.id}: {x.error}</div>)}</div>}
        <div className="row" style={{ justifyContent: 'flex-end', gap: 8 }}>
          {rows.length > 0 && <button className="btn btn-soft btn-sm" onClick={copy}>คัดลอกทั้งหมด</button>}
          {rows.length > 0 && <button className="btn btn-soft btn-sm" onClick={download}>ดาวน์โหลด CSV</button>}
          <button className="btn btn-coral btn-sm" onClick={onClose}>ปิด</button>
        </div>
      </div>
    </window.ModalShell>
  );
}

window.EmployeePage = EmployeePage;
