/* global React, window, Icon, Toggle */
const { useState: useStateSettings, useEffect: useEffectSettings } = React;

// Settings stored as strings in DB. Helpers to normalise on read/write.
const isOn = (v) => v === 'true' || v === true || v === '1' || v === 1;
const onOff = (b) => (b ? 'true' : 'false');

function SettingsPage({ role }) {
  const [section, setSection] = useStateSettings('event');
  const [settings, setSettings] = useStateSettings({});
  const [dirty, setDirty] = useStateSettings(false);
  const [saving, setSaving] = useStateSettings(false);
  const [saveMsg, setSaveMsg] = useStateSettings('');
  // Subscribe to global refresh so device dropdowns / user list reflect adds/edits
  window.useDataVersion();

  // Fetch current settings on mount
  useEffectSettings(() => {
    (async () => {
      try {
        const r = await fetch('/api/settings', { credentials: 'include' });
        if (r.ok) {
          const d = await r.json();
          setSettings(d.settings || {});
        }
      } catch (_) {}
    })();
  }, []);

  // Field update helper passed to child sections
  const set = (key, value) => {
    setSettings((s) => {
      const next = { ...s, [key]: value };
      // Live preview for theme settings so admin can see the new color/font
      // before pressing save
      if (key.startsWith('theme_') && window.applyTheme) window.applyTheme(next);
      return next;
    });
    setDirty(true);
    setSaveMsg('');
  };

  const save = async () => {
    if (saving) return;
    setSaving(true); setSaveMsg('');
    try {
      const r = await fetch('/api/settings', {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(settings),
      });
      const data = await r.json().catch(() => ({}));
      if (!r.ok) {
        throw new Error(data.error || `error ${r.status}`);
      }
      // Re-fetch saved values from DB so we see exactly what got persisted
      const verify = await fetch('/api/settings', { credentials: 'include' });
      if (verify.ok) {
        const vd = await verify.json();
        setSettings(vd.settings || settings);
      }
      // Refresh global SETTINGS so topbar / dashboard pick up new event_name etc.
      if (window.refreshData) {
        try { await window.refreshData(); } catch (_) {}
      }
      setSaveMsg('✓ บันทึกการเปลี่ยนแปลงแล้ว (' + new Date().toLocaleTimeString('th-TH') + ')');
      setDirty(false);
    } catch (e) {
      setSaveMsg('✗ ' + e.message);
      console.error('[settings] save failed:', e);
    } finally {
      setSaving(false);
      // Keep success message visible longer so user actually sees it
      setTimeout(() => setSaveMsg(''), 8000);
    }
  };

  const sections = [
    { id: 'event',    label: 'ข้อมูลองค์กร',     icon: 'sparkles' },
    { id: 'attend',   label: 'การลงเวลา',        icon: 'clock' },
    { id: 'access',   label: 'ผู้ใช้งานระบบ',     icon: 'shield' },
    { id: 'data',     label: 'ข้อมูล & สำรอง',   icon: 'refresh' },
    { id: 'theme',    label: 'รูปลักษณ์',          icon: 'sparkles' },
    { id: 'about',    label: 'เกี่ยวกับระบบ',     icon: 'sparkles' },
  ];

  return (
    <div data-screen-label="Settings">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 16, flexWrap: 'wrap', marginBottom: 18 }}>
        <div>
          <h1 style={{ fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 700, margin: 0 }}>ตั้งค่าระบบ / Settings</h1>
          <div style={{ fontSize: 12.5, color: 'var(--ink-4)', marginTop: 4 }}>กำหนดข้อมูลองค์กร การเข้าใช้งาน และพฤติกรรมของระบบลงเวลา</div>
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
          {saveMsg && (
            <span style={{
              fontSize: 12.5, fontWeight: 600,
              color: saveMsg.startsWith('✓') ? 'var(--mint-ink)' : 'var(--coral-ink)',
            }}>{saveMsg}</span>
          )}
          <button
            className="gv-btn ok sm"
            onClick={save}
            disabled={saving || !dirty}
            title={!dirty ? 'ไม่มีการเปลี่ยนแปลง' : ''}
          >
            <Icon name="check" size={13}/>
            {saving ? 'กำลังบันทึก…' : 'บันทึกการเปลี่ยนแปลง'}
          </button>
        </div>
      </div>

      <div style={{display: 'grid', gridTemplateColumns: '240px 1fr', gap: 18}}>
        <div className="gv-card" style={{padding: 8, position: 'sticky', top: 100, alignSelf: 'flex-start'}}>
          <div style={{display: 'flex', flexDirection: 'column', gap: 2}}>
            {sections.map(s => (
              <button key={s.id} onClick={() => setSection(s.id)} style={{
                display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px',
                borderRadius: 12, border: 0, width: '100%',
                background: section === s.id ? 'var(--surface-2)' : 'transparent',
                color: section === s.id ? 'var(--ink)' : 'var(--ink-4)',
                fontWeight: section === s.id ? 600 : 500,
                fontFamily: 'inherit', fontSize: 13.5,
                cursor: 'pointer', textAlign: 'left',
              }}>
                <Icon name={s.icon} size={15}/>
                {s.label}
                {section === s.id && <Icon name="chevron-right" size={14} style={{marginLeft: 'auto'}}/>}
              </button>
            ))}
          </div>
        </div>

        <div>
          {section === 'event' && <EventSection settings={settings} set={set}/>}
          {section === 'attend' && <AttendSection settings={settings} set={set}/>}
          {section === 'access' && <AccessSection settings={settings} set={set}/>}
          {section === 'data' && <DataSection settings={settings} set={set}/>}
          {section === 'theme' && <ThemeSection settings={settings} set={set}/>}
          {section === 'about' && <AboutSection/>}
        </div>
      </div>
    </div>
  );
}

function SectionCard({ title, desc, children }) {
  return (
    <div className="gv-card" style={{marginBottom: 14}}>
      <div className="gv-card-h"><b>{title}</b></div>
      <div className="gv-card-b" style={{display: 'flex', flexDirection: 'column', gap: 14}}>
        {desc && <div style={{fontSize: 12.5, color: 'var(--ink-4)', marginTop: -2}}>{desc}</div>}
        {children}
      </div>
    </div>
  );
}

function SettingRow({ label, desc, children }) {
  return (
    <div className="gv-row" style={{justifyContent: 'space-between', alignItems: 'flex-start', gap: 16}}>
      <div style={{flex: 1, minWidth: 0}}>
        <div style={{fontWeight: 600, fontSize: 13.5}}>{label}</div>
        {desc && <div style={{fontSize: 12.5, color: 'var(--ink-4)', marginTop: 2}}>{desc}</div>}
      </div>
      <div style={{display: 'flex', gap: 8, flex: 'none', alignItems: 'center'}}>
        {children}
      </div>
    </div>
  );
}

function EventSection({ settings, set }) {
  const v = (k) => settings[k] || '';
  const fileRef = React.useRef(null);
  const [uploading, setUploading] = React.useState(false);
  const [uploadErr, setUploadErr] = React.useState('');
  const logoUrl = v('event_logo_url');

  // Organization-type mode (company / government). Read from the global that
  // was hydrated at bootstrap; changing it re-PUTs settings and reloads so all
  // window.T labels refresh everywhere.
  const orgType = (window.SETTINGS && window.SETTINGS.org_type) === 'government' ? 'government' : 'company';
  const changeOrgType = async (value) => {
    if (value === orgType) return;
    try {
      const body = { org_type: value };
      // Government standard is a single 08:30–16:30 shift.
      if (value === 'government') { body.gov_work_start = '08:30'; body.gov_work_end = '16:30'; }
      await fetch('/api/settings', {
        method: 'PUT', credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      });
    } catch (_) {}
    window.location.reload();
  };

  const pickLogo = () => fileRef.current?.click();

  const uploadLogo = async (file) => {
    if (!file) return;
    setUploadErr(''); setUploading(true);
    try {
      const fd = new FormData();
      fd.append('logo', file);
      const r = await fetch('/api/settings/logo', {
        method: 'POST', credentials: 'include', body: fd,
      });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || `error ${r.status}`);
      // Update in-memory setting so the new logo shows immediately
      set('event_logo_url', d.url);
      if (window.refreshData) await window.refreshData();
    } catch (e) {
      setUploadErr(e.message);
    } finally {
      setUploading(false);
      if (fileRef.current) fileRef.current.value = '';
    }
  };

  const removeLogo = async () => {
    const ok = await window.appConfirm({
      title: 'ลบโลโก้',
      message: 'จะลบโลโก้องค์กรออก — ระบบจะใช้โลโก้ default แทน',
      confirmText: 'ลบโลโก้',
      danger: true,
    });
    if (!ok) return;
    try {
      await fetch('/api/settings/logo', { method: 'DELETE', credentials: 'include' });
      set('event_logo_url', '');
      if (window.refreshData) await window.refreshData();
      window.appToast('ลบโลโก้แล้ว', { tone: 'success' });
    } catch (_) {}
  };

  return (
    <SectionCard title="ข้อมูลองค์กร" desc="ชื่อและโลโก้องค์กรที่จะแสดงบน masthead, บัตรพนักงาน และหน้าจอเครื่องสแกน">
      <div style={{display: 'flex', gap: 14, padding: 14, background: 'var(--surface-2)', borderRadius: 'var(--r-md)'}}>
        <div style={{
          width: 72, height: 72, borderRadius: 18, flex: 'none',
          background: logoUrl ? '#fff' : 'linear-gradient(135deg, var(--primary), var(--magenta))',
          display: 'grid', placeItems: 'center', overflow: 'hidden',
          border: logoUrl ? '1px solid var(--line)' : 'none', color: '#fff',
        }}>
          {logoUrl ? (
            <img src={logoUrl} alt="logo" style={{width: '100%', height: '100%', objectFit: 'contain'}}/>
          ) : (
            <Icon name="sparkles" size={28} stroke={2}/>
          )}
        </div>
        <div style={{flex: 1}}>
          <div style={{fontSize: 11.5, color: 'var(--ink-4)', marginBottom: 4}}>โลโก้องค์กร</div>
          <input ref={fileRef} type="file" accept="image/png,image/jpeg,image/webp" style={{display: 'none'}}
            onChange={(e) => uploadLogo(e.target.files?.[0])}/>
          <div style={{display: 'flex', gap: 6}}>
            <button type="button" className="gv-btn no sm" onClick={pickLogo} disabled={uploading}>
              <Icon name="upload" size={13}/>{uploading ? 'กำลังอัปโหลด…' : (logoUrl ? 'เปลี่ยนโลโก้' : 'อัปโหลดโลโก้')}
            </button>
            {logoUrl && (
              <button type="button" className="gv-btn danger sm" onClick={removeLogo}>
                <Icon name="trash" size={12}/>ลบ
              </button>
            )}
          </div>
          <div style={{fontSize: 11, color: 'var(--ink-4)', marginTop: 6}}>PNG, JPG, WebP · สูงสุด 2MB · แนะนำ 256×256 px</div>
          {uploadErr && (
            <div style={{marginTop: 6, fontSize: 12, color: 'var(--coral-ink)', fontWeight: 600}}>✗ {uploadErr}</div>
          )}
        </div>
      </div>

      <div className="gv-field" style={{marginBottom: 0}}>
        <label>ชื่อองค์กร / หน่วยงาน</label>
        <input className="gv-input" placeholder="เช่น บริษัท กู๊ดไซเบอร์ จำกัด" value={v('org_name') || v('event_name')}
          onChange={(e) => { set('org_name', e.target.value); set('event_name', e.target.value); }}/>
        <div style={{fontSize: 11.5, color: 'var(--ink-4)', marginTop: 4}}>แสดงเป็นชื่อใหญ่บน masthead และหัวบัตรพนักงาน</div>
      </div>

      <div className="gv-field" style={{marginBottom: 0}}>
        <label>คำอธิบาย</label>
        <textarea className="gv-textarea" rows={2} value={v('event_description')}
          onChange={(e) => set('event_description', e.target.value)}/>
      </div>

      <div style={{display: 'flex', gap: 12}}>
        <div className="gv-field" style={{flex: 2, marginBottom: 0}}>
          <label>ที่อยู่ / สถานที่ตั้ง</label>
          <input className="gv-input" placeholder="เช่น สำนักงานใหญ่ ชั้น 5" value={v('event_venue')}
            onChange={(e) => set('event_venue', e.target.value)}/>
        </div>
        <div className="gv-field" style={{flex: 1, marginBottom: 0}}>
          <label>โซนเวลา</label>
          <select className="gv-select" value={v('event_timezone') || 'Asia/Bangkok'}
            onChange={(e) => set('event_timezone', e.target.value)}>
            <option value="Asia/Bangkok">(GMT+7) กรุงเทพมหานคร</option>
            <option value="Asia/Singapore">(GMT+8) สิงคโปร์</option>
            <option value="Asia/Tokyo">(GMT+9) โตเกียว</option>
            <option value="UTC">(GMT+0) UTC</option>
          </select>
        </div>
      </div>

      <div className="gv-field" style={{ marginBottom: 0 }}>
        <label>ประเภทหน่วยงาน</label>
        <div className="gv-seg" style={{ display: 'inline-flex', width: 'fit-content' }}>
          <button type="button" className={orgType === 'company' ? 'on' : ''} onClick={() => changeOrgType('company')}>บริษัท</button>
          <button type="button" className={orgType === 'government' ? 'on' : ''} onClick={() => changeOrgType('government')}>หน่วยงานราชการ</button>
        </div>
        <div style={{ fontSize: 11.5, color: 'var(--ink-4)', marginTop: 6 }}>
          สลับคำเรียกทั่วทั้งระบบ — {orgType === 'government' ? 'กอง · เจ้าหน้าที่ · หน่วยงาน' : 'แผนก · พนักงาน · บริษัท'}
        </div>
        {orgType === 'government' && (
          <div style={{ fontSize: 11.5, color: 'var(--ink-4)', marginTop: 4 }}>
            เวลาราชการมาตรฐาน 08:30–16:30 น. (กะเดียว)
          </div>
        )}
      </div>
    </SectionCard>
  );
}

function UserEditModal({ user, onClose, onSaved }) {
  const isNew = !user;
  const [username, setUsername] = React.useState(user?.username || '');
  const [displayName, setDisplayName] = React.useState(user?.display_name || '');
  const [password, setPassword] = React.useState('');
  const [role, setRole] = React.useState(user?.role || 'viewer');
  const [deviceId, setDeviceId] = React.useState(user?.device_id || '');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  // operator (viewer) MUST have a device → auto-pick first
  React.useEffect(() => {
    if (role !== 'admin' && !deviceId && window.DEVICES.length) {
      setDeviceId(window.DEVICES[0].db_id);
    }
    if (role === 'admin') setDeviceId('');
  }, [role]);

  const save = async (e) => {
    e.preventDefault();
    setErr(''); setBusy(true);
    try {
      if (isNew) {
        if (!username.trim()) throw new Error('ระบุ username');
        if (!password || password.length < 4) throw new Error('รหัสผ่านอย่างน้อย 4 ตัวอักษร');
        const body = {
          username: username.trim(),
          password,
          display_name: displayName.trim(),
          role: role === 'admin' ? 'admin' : 'viewer',
          device_id: role === 'admin' ? null : (deviceId ? Number(deviceId) : null),
        };
        const r = await fetch('/api/users', {
          method: 'POST', credentials: 'include',
          headers: {'Content-Type':'application/json'}, body: JSON.stringify(body),
        });
        if (!r.ok) throw new Error((await r.json()).error || 'สร้างไม่สำเร็จ');
      } else {
        const r = await fetch(`/api/users/${user.id}`, {
          method: 'PUT', credentials: 'include',
          headers: {'Content-Type':'application/json'},
          body: JSON.stringify({
            display_name: displayName.trim(),
            role: role === 'admin' ? 'admin' : 'viewer',
            device_id: role === 'admin' ? null : (deviceId ? Number(deviceId) : null),
          }),
        });
        if (!r.ok) throw new Error((await r.json()).error || 'แก้ไขไม่สำเร็จ');
        if (password) {
          const r2 = await fetch(`/api/users/${user.id}/password`, {
            method: 'PUT', credentials: 'include',
            headers: {'Content-Type':'application/json'},
            body: JSON.stringify({ new_password: password }),
          });
          if (!r2.ok) throw new Error('แก้รหัสไม่สำเร็จ');
        }
      }
      onSaved();
    } catch (e2) {
      setErr(e2.message);
    } finally {
      setBusy(false);
    }
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(15,23,42,.45)',
      display: 'grid', placeItems: 'center', padding: 20,
    }}>
      <form className="gv-card" onClick={(e) => e.stopPropagation()} onSubmit={save} style={{
        width: 'min(440px, 96vw)', maxHeight: '90vh', overflow: 'auto',
      }}>
        <div className="gv-card-h"><b>{isNew ? 'เพิ่มผู้ใช้' : 'แก้ไขผู้ใช้'}</b></div>
        <div className="gv-card-b">
          <div style={{fontSize: 12.5, color: 'var(--ink-4)', marginBottom: 16}}>
            {isNew ? 'ตั้ง username/รหัสผ่าน + เลือกบทบาท' : `${user.username}`}
          </div>

          <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
            <div className="gv-field" style={{marginBottom: 0}}>
              <label>Username</label>
              <input className="gv-input" value={username} onChange={(e) => setUsername(e.target.value)}
                disabled={!isNew} placeholder="fsct1, admin, op101 …" autoComplete="off"/>
            </div>

            <div className="gv-field" style={{marginBottom: 0}}>
              <label>ชื่อแสดง (ไม่บังคับ)</label>
              <input className="gv-input" value={displayName} onChange={(e) => setDisplayName(e.target.value)}
                placeholder="เช่น นายอภิวัฒน์ สรรพชัย"/>
            </div>

            <div className="gv-field" style={{marginBottom: 0}}>
              <label>{isNew ? 'รหัสผ่าน' : 'รหัสผ่านใหม่ (เว้นว่าง = ไม่เปลี่ยน)'}</label>
              <input className="gv-input" type="password" value={password} onChange={(e) => setPassword(e.target.value)}
                placeholder={isNew ? 'อย่างน้อย 4 ตัวอักษร' : '••••'} autoComplete="new-password"/>
            </div>

            <div className="gv-field" style={{marginBottom: 0}}>
              <label>บทบาท</label>
              <div style={{display: 'flex', gap: 8}}>
                <button type="button" className={`gv-btn ${role === 'admin' ? 'dark' : 'no'} sm`}
                  onClick={() => setRole('admin')} style={{flex: 1}}>ผู้ดูแลระบบ</button>
                <button type="button" className={`gv-btn ${role !== 'admin' ? 'dark' : 'no'} sm`}
                  onClick={() => setRole('viewer')} style={{flex: 1}}>ประจำเครื่อง</button>
              </div>
              <div style={{fontSize: 11.5, color: 'var(--ink-4)', marginTop: 6}}>
                {role === 'admin'
                  ? 'เข้าได้ทุกหน้า เห็นข้อมูลทุกเครื่อง'
                  : 'ล็อกที่หน้า "ลงทะเบียนเข้างาน" + เห็นเฉพาะเครื่องที่ผูก'}
              </div>
            </div>

            {role !== 'admin' && (
              <div className="gv-field" style={{marginBottom: 0}}>
                <label>ผูกกับเครื่อง</label>
                <select className="gv-select" value={deviceId} onChange={(e) => setDeviceId(e.target.value)}>
                  <option value="">— เลือกเครื่อง —</option>
                  {window.DEVICES.map((d) => (
                    <option key={d.db_id} value={d.db_id}>
                      {d.id} · {d.name} ({d.ip}) {d.status === 'online' ? '· ออนไลน์' : ''}
                    </option>
                  ))}
                </select>
              </div>
            )}

            {err && (
              <div style={{
                padding: '10px 14px', borderRadius: 10,
                background: 'var(--coral-soft)',
                color: 'var(--coral-ink)', fontSize: 12.5, fontWeight: 600,
              }}>{err}</div>
            )}
          </div>

          <div style={{display: 'flex', gap: 8, marginTop: 18}}>
            <button type="button" className="gv-btn no" onClick={onClose} style={{flex: 1}}>ยกเลิก</button>
            <button type="submit" className="gv-btn ok" disabled={busy} style={{flex: 1}}>
              {busy ? 'กำลังบันทึก…' : 'บันทึก'}
            </button>
          </div>
        </div>
      </form>
    </div>
  );
}

function AccessSection({ settings = {}, set = () => {} }) {
  const [users, setUsers] = React.useState([]);
  const [editing, setEditing] = React.useState(null);   // user object | 'new' | null
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  const load = React.useCallback(async () => {
    try {
      const r = await fetch('/api/users', { credentials: 'include' });
      if (r.ok) setUsers(await r.json());
    } catch (_) {}
  }, []);
  React.useEffect(() => { load(); }, [load]);

  const deleteUser = async (id) => {
    const ok = await window.appConfirm({
      title: 'ลบผู้ใช้นี้',
      message: 'ผู้ใช้จะไม่สามารถเข้าระบบได้อีก — การกระทำนี้ย้อนกลับไม่ได้',
      confirmText: 'ลบ',
      danger: true,
    });
    if (!ok) return;
    const r = await fetch(`/api/users/${id}`, { method: 'DELETE', credentials: 'include' });
    if (r.ok) {
      load();
      window.appToast('ลบผู้ใช้แล้ว', { tone: 'success' });
    } else {
      const d = await r.json().catch(() => ({}));
      window.appToast(d.error || 'ลบไม่สำเร็จ', { tone: 'error' });
    }
  };

  const colorOf = (u) => {
    if (u.role === 'admin') return 'coral';
    if (u.device_id) return ['mint', 'indigo', 'magenta', 'yellow', 'cyan'][(u.device_id - 1) % 5];
    return 'indigo';
  };
  // map avatar palette name → a hrzoft token background
  const AVA_BG = { coral: 'var(--coral)', mint: 'var(--mint)', indigo: 'var(--magenta)', magenta: 'var(--magenta)', yellow: 'var(--yellow)', cyan: 'var(--primary)' };

  const labelOf = (u) => {
    if (u.role === 'admin') return 'ผู้ดูแลระบบ';
    if (u.device_id) {
      const dev = window.DEVICES.find((d) => d.db_id === u.device_id);
      return `Operator (${dev ? dev.id : '#' + u.device_id})`;
    }
    return 'Viewer';
  };

  return (
    <>
      <SectionCard title="ผู้ใช้งานระบบ" desc="กำหนดสิทธิ์การเข้าถึง: admin (ดูแลทั้งระบบ) · hr · manager (เฉพาะแผนก) · employee">
        <div style={{display: 'flex', flexDirection: 'column', gap: 8}}>
          {users.length === 0 && (
            <div className="gv-empty">กำลังโหลด…</div>
          )}
          {users.map((u) => (
            <div key={u.id} style={{display: 'flex', alignItems: 'center', gap: 12, padding: 12, background: 'var(--surface-2)', borderRadius: 'var(--r-md)'}}>
              <div style={{
                width: 38, height: 38, borderRadius: '50%', flex: 'none',
                display: 'grid', placeItems: 'center', color: '#fff',
                fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 14,
                background: AVA_BG[colorOf(u)] || 'var(--magenta)',
              }}>{(u.display_name || u.username).charAt(0).toUpperCase()}</div>
              <div style={{flex: 1, minWidth: 0}}>
                <div style={{fontWeight: 600, fontSize: 13.5}}>{u.display_name || u.username}</div>
                <div style={{fontSize: 12, color: 'var(--ink-4)'}}>{u.username}{u.device_name ? ` · ${u.device_name}` : ''}</div>
              </div>
              <span className="gv-chip c-gray">{labelOf(u)}</span>
              <button className="gv-btn no sm" onClick={() => setEditing(u)}><Icon name="edit" size={12}/></button>
              {u.role !== 'admin' && (
                <button className="gv-btn danger sm" onClick={() => deleteUser(u.id)}>
                  <Icon name="x" size={12}/>
                </button>
              )}
            </div>
          ))}
        </div>
        <button className="gv-btn no" style={{alignSelf: 'flex-start', marginTop: 8}} onClick={() => setEditing('new')}>
          <Icon name="plus" size={13}/>เพิ่มผู้ใช้
        </button>
      </SectionCard>

      {editing && (
        <UserEditModal
          user={editing === 'new' ? null : editing}
          onClose={() => { setEditing(null); setErr(''); }}
          onSaved={() => { setEditing(null); load(); }}
        />
      )}
    </>
  );
}

// การลงเวลา — scan_interval_sec is read live by the backend event-processor.
function AttendSection({ settings = {}, set = () => {} }) {
  const interval = settings.scan_interval_sec != null ? settings.scan_interval_sec : '60';
  return (
    <SectionCard title="พฤติกรรมการลงเวลา" desc="กฎการนับสแกนเข้า-ออกจากเครื่อง Hikvision">
      <SettingRow label="ช่วงเวลาสแกนซ้ำขั้นต่ำ" desc="สแกนซ้ำภายในเวลานี้จะไม่นับเป็นการลงเวลาใหม่ (กันเด้งเป็น 'ออกงาน' ทันที)">
        <input className="gv-input" type="number" min="0" style={{width: 90, textAlign: 'right'}}
          value={interval} onChange={(e) => set('scan_interval_sec', e.target.value)}/>
        <span style={{fontSize: 12, color: 'var(--ink-4)'}}>วินาที</span>
      </SettingRow>
      <div style={{fontSize: 12.5, color: 'var(--ink-4)', marginTop: 4, lineHeight: 1.6}}>
        • สแกน<b>แรก</b>ของวัน = เข้างาน · สแกน<b>สุดท้าย</b> = ออกงาน<br/>
        • เวลาเข้า/สาย/OT คิดตาม<b>กะ</b>ของพนักงาน — ตั้งกะที่เมนู “ตารางกะ” และผูกกะที่หน้า “พนักงาน”<br/>
        • ระบบใช้<b>เวลาจริงจากเครื่อง</b> และทิ้ง event ค้างเก่าอัตโนมัติ (กันข้อมูลซ้ำ)
      </div>
    </SectionCard>
  );
}

// ข้อมูล & สำรอง — real backup (POST /api/admin/backup/run) + sync faces to devices.
function DataSection() {
  const [files, setFiles] = React.useState([]);
  const [busy, setBusy] = React.useState('');
  const loadBackups = React.useCallback(async () => {
    try { const r = await fetch('/api/admin/backup', { credentials: 'include' }); if (r.ok) { const d = await r.json(); setFiles(d.files || []); } } catch (_) {}
  }, []);
  React.useEffect(() => { loadBackups(); }, [loadBackups]);

  const runBackup = async () => {
    setBusy('backup');
    try {
      const r = await fetch('/api/admin/backup/run', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: '{}' });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'ล้มเหลว');
      window.appToast('สำรองข้อมูลแล้ว', { tone: 'success' });
      loadBackups();
    } catch (e) { window.appToast('สำรองไม่สำเร็จ: ' + e.message, { tone: 'error' }); }
    finally { setBusy(''); }
  };
  const syncAll = async () => {
    const ok = await window.appConfirm({ title: 'Sync ใบหน้าทั้งหมดไปทุกเครื่อง?', message: 'อาจใช้เวลาหลายนาที', confirmText: 'Sync' });
    if (!ok) return;
    setBusy('sync');
    try {
      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: d.synced ? 'success' : 'info' });
    } catch (e) { window.appToast('Sync ไม่สำเร็จ', { tone: 'error' }); }
    finally { setBusy(''); }
  };
  const fmtSize = (b) => b > 1e6 ? (b / 1e6).toFixed(1) + ' MB' : Math.round(b / 1e3) + ' KB';

  return (
    <>
      <SectionCard title="สำรองข้อมูล" desc="สำรองฐานข้อมูลทั้งหมด (พนักงาน · การลงเวลา · ตั้งค่า) — อัตโนมัติทุกวัน + กดเองได้">
        <button className="gv-btn ok" style={{ alignSelf: 'flex-start' }} onClick={runBackup} disabled={busy === 'backup'}>
          <Icon name="download" size={13}/>{busy === 'backup' ? 'กำลังสำรอง…' : 'สำรองข้อมูลตอนนี้'}
        </button>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 12 }}>
          {files.length === 0 ? (
            <div style={{ fontSize: 12.5, color: 'var(--ink-4)' }}>ยังไม่มีไฟล์สำรอง</div>
          ) : files.slice(0, 10).map((b) => (
            <div key={b.name} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, fontSize: 12.5, padding: '7px 12px', background: 'var(--surface-2)', borderRadius: 10 }}>
              <span style={{ fontFamily: 'var(--font-mono, monospace)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{b.name}</span>
              <span style={{ color: 'var(--ink-4)', flex: 'none' }}>{fmtSize(b.size_bytes)}</span>
              <a className="gv-btn no sm" style={{ flex: 'none' }} href={`/api/admin/backup/${encodeURIComponent(b.name)}/download`}>โหลด</a>
            </div>
          ))}
        </div>
      </SectionCard>

      <SectionCard title="ซิงค์ใบหน้าไปเครื่องสแกน" desc="ส่งรูป + ข้อมูลพนักงานทั้งหมดไปยังเครื่อง Hikvision ทุกตัว (ระบบย่อรูปให้พอดีเครื่องอัตโนมัติ)">
        <button className="gv-btn no" style={{ alignSelf: 'flex-start' }} onClick={syncAll} disabled={busy === 'sync'}>
          <Icon name="refresh" size={13}/>{busy === 'sync' ? 'กำลัง Sync…' : 'Sync ใบหน้าทั้งหมด'}
        </button>
      </SectionCard>
    </>
  );
}

function ThemeSection({ settings = {}, set = () => {} }) {
  const mode = settings.theme_mode || 'light';
  const primary = settings.theme_primary || 'coral';
  const density = settings.theme_density || 'normal';
  const fontSize = settings.theme_font_size || '14';

  return (
    <SectionCard title="รูปลักษณ์" desc="กำหนดธีมและสีของระบบ">
      <SettingRow label="ธีม">
        <div className="gv-seg">
          <button className={mode === 'light' ? 'on' : ''} onClick={() => set('theme_mode', 'light')}><Icon name="sun" size={12}/>Light</button>
          <button className={mode === 'dark' ? 'on' : ''} onClick={() => set('theme_mode', 'dark')}><Icon name="moon" size={12}/>Dark</button>
          <button className={mode === 'auto' ? 'on' : ''} onClick={() => set('theme_mode', 'auto')}>Auto</button>
        </div>
      </SettingRow>
      <SettingRow label="สีหลัก">
        <div style={{display: 'flex', gap: 6}}>
          {['coral', 'primary', 'mint', 'magenta', 'cyan'].map(c => (
            <button key={c} type="button" onClick={() => set('theme_primary', c)}
              style={{
                width: 28, height: 28, borderRadius: 8, background: `var(--${c})`,
                border: primary === c ? '2px solid var(--ink)' : '2px solid transparent',
                cursor: 'pointer',
              }}/>
          ))}
        </div>
      </SettingRow>
      <SettingRow label="ความหนาแน่นของ UI">
        <div className="gv-seg">
          <button className={density === 'compact' ? 'on' : ''} onClick={() => set('theme_density', 'compact')}>กระชับ</button>
          <button className={density === 'normal' ? 'on' : ''} onClick={() => set('theme_density', 'normal')}>ปกติ</button>
          <button className={density === 'spacious' ? 'on' : ''} onClick={() => set('theme_density', 'spacious')}>โล่ง</button>
        </div>
      </SettingRow>
      <SettingRow label={`ขนาดตัวอักษร (${fontSize}px)`}>
        <input type="range" min="12" max="18" value={fontSize}
          onChange={(e) => set('theme_font_size', e.target.value)} style={{width: 140}}/>
      </SettingRow>
    </SectionCard>
  );
}

function AboutSection() {
  return (
    <SectionCard title="เกี่ยวกับ FaceInTime">
      <div style={{display: 'flex', alignItems: 'center', gap: 18, padding: 18, background: 'var(--surface-2)', borderRadius: 'var(--r-md)'}}>
        <div style={{width: 56, height: 56, borderRadius: 16, flex: 'none', background: 'linear-gradient(135deg, var(--primary), var(--magenta))'}}/>
        <div>
          <div style={{fontFamily: 'var(--font-display)', fontSize: 20, fontWeight: 700}}>FaceInTime</div>
          <div style={{fontSize: 13, color: 'var(--ink-4)'}}>ระบบลงเวลาทำงานด้วยการสแกนใบหน้า (Hikvision Face Terminal)</div>
          <div style={{display: 'flex', gap: 14, marginTop: 8, fontSize: 12, color: 'var(--ink-4)'}}>
            <span>เวอร์ชั่น <span style={{fontFamily: 'var(--font-mono, monospace)', fontWeight: 600}}>v1.0.0</span></span>
            <span>·</span>
            <span>hrzoft</span>
          </div>
        </div>
      </div>
      <SettingRow label="ข้อมูลลิขสิทธิ์"><span style={{fontSize: 12, color: 'var(--ink-4)'}}>© 2026 GoodCyber</span></SettingRow>
      <SettingRow label="สนับสนุน Hikvision SDK"><span className="gv-chip c-green">V6.1.8.15</span></SettingRow>
      <SettingRow label="License">
        <span className="gv-chip c-blue">Enterprise · ไม่จำกัด</span>
      </SettingRow>
    </SectionCard>
  );
}

window.SettingsPage = SettingsPage;
