/* [NALA_ABSEN_V1][NALA_ABSEN_V2] Absensi staff — punch PIN 4 aksi, multi-sesi + istirahat,
   papan harian, rekap, kelola (jadwal 2 jendela). Copy UI FORMAL (Anda/silakan).
   IIFE-wrapped (babel-standalone share global scope). Expose: window.AbsenTab */
(() => {
const {useState, useEffect} = React;

const jGet = (u)=>fetch(u,{credentials:'include'}).then(async r=>{const d=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(typeof d.detail==='string'?d.detail:(d.detail?.error||r.statusText));e.status=r.status;throw e}return d});
const jPost = (u,b)=>fetch(u,{method:'POST',credentials:'include',headers:{'Content-Type':'application/json'},body:JSON.stringify(b||{})}).then(async r=>{const d=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(typeof d.detail==='string'?d.detail:(d.detail?.error||r.statusText));e.status=r.status;throw e}return d});
const jPatch = (u,b)=>fetch(u,{method:'PATCH',credentials:'include',headers:{'Content-Type':'application/json'},body:JSON.stringify(b||{})}).then(async r=>{const d=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(typeof d.detail==='string'?d.detail:(d.detail?.error||r.statusText));e.status=r.status;throw e}return d});
const jDel = (u)=>fetch(u,{method:'DELETE',credentials:'include'}).then(async r=>{const d=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(typeof d.detail==='string'?d.detail:(d.detail?.error||r.statusText));e.status=r.status;throw e}return d});

const hhmm = (iso)=> iso ? iso.slice(11,16) : '–';
const fmtMin = (m)=> m>=60 ? `${Math.floor(m/60)}j ${m%60}m` : `${m}m`;
const ACTION_LABEL = {in:'MASUK', break_out:'ISTIRAHAT', break_in:'KEMBALI', out:'PULANG'};
const STATUS_META = {
  hadir: {label:'Hadir', cls:'ab-pill ab-hadir'},
  telat: {label:'Telat', cls:'ab-pill ab-telat'},
  istirahat: {label:'Istirahat', cls:'ab-pill ab-break'},
  belum: {label:'Belum absen', cls:'ab-pill ab-belum'},
  libur: {label:'Libur', cls:'ab-pill ab-libur'},
};

/* ---------------- PUNCH + BOARD ---------------- */
function PunchBoard(){
  const [board,setBoard]=useState(null);
  const [selId,setSelId]=useState(null);
  const [pin,setPin]=useState('');
  const [busy,setBusy]=useState(false);
  const [msg,setMsg]=useState(null);
  const load=()=>jGet('/api/absen/today').then(setBoard).catch(e=>setMsg({ok:false,text:e.message}));
  useEffect(()=>{load(); const iv=setInterval(load,60000); return ()=>clearInterval(iv)},[]);

  const punch=async(action)=>{
    if(!selId) return;
    if(pin.length<4){setMsg({ok:false,text:'PIN minimal 4 digit'});return}
    setBusy(true);setMsg(null);
    try{
      const r=await jPost('/api/absen/punch',{staff_id:selId,action,pin});
      setMsg({ok:true,text:`${r.name} — ${ACTION_LABEL[action]} tercatat ${hhmm(r.at)}${r.late?' (TELAT)':''}`});
      setPin('');setSelId(null);load();
    }catch(e){setMsg({ok:false,text:e.message})}
    setBusy(false);
  };

  if(!board) return <div className="empty-state">Memuat…</div>;
  const sel = selId ? board.rows.find(r=>r.staff_id===selId) : null;
  const openSession = sel && sel.sessions.some(s=>!s.checkout_at);
  const onBreak = sel && !!sel.on_break_since;
  const canIn    = sel && !openSession;
  const canBreak = sel && openSession && !onBreak;
  const canBack  = sel && onBreak;
  const canOut   = sel && openSession && !onBreak;
  return <div>
    <div className="card" style={{padding:18,marginBottom:16}}>
      <h3 style={{marginBottom:12}}>Absen — Pilih Nama Anda</h3>
      <div className="ab-name-grid">
        {board.rows.map(r=>(
          <button key={r.staff_id}
                  className={'ab-name-btn '+(selId===r.staff_id?'active':'')}
                  onClick={()=>{setSelId(r.staff_id);setMsg(null);setPin('')}}>
            {r.name}{!r.pin_set && <span className="ab-nopin" title="PIN belum diatur oleh admin"> ⚠</span>}
          </button>
        ))}
      </div>
      {sel && <div className="ab-punch-panel">
        <div className="muted" style={{fontSize:12,marginBottom:8}}>
          {sel.name} · jadwal hari ini: {sel.is_off?'Libur':(sel.schedule||'-')}
          {onBreak && <span> · sedang istirahat sejak {hhmm(sel.on_break_since)}</span>}
        </div>
        <input className="ab-pin" type="password" inputMode="numeric" pattern="[0-9]*" maxLength={6}
               placeholder="PIN" value={pin} onChange={e=>setPin(e.target.value.replace(/\D/g,''))}/>
        <div className="ab-actions">
          <button className="btn btn-primary" disabled={busy||!canIn} onClick={()=>punch('in')}>Masuk</button>
          <button className="btn btn-ghost" disabled={busy||!canBreak} onClick={()=>punch('break_out')}>Istirahat</button>
          <button className="btn btn-ghost" disabled={busy||!canBack} onClick={()=>punch('break_in')}>Kembali</button>
          <button className="btn btn-ghost" disabled={busy||!canOut} onClick={()=>punch('out')}>Pulang</button>
        </div>
      </div>}
      {msg && <div className={'ab-msg '+(msg.ok?'ok':'err')}>{msg.text}</div>}
    </div>

    <div className="card">
      <div className="card-h"><h3>Hari Ini — {board.date}</h3>
        <span className="muted" style={{fontSize:11}}>toleransi {board.tolerance_min} mnt · maks istirahat {board.max_break_min} mnt</span></div>
      <table className="ab-table">
        <thead><tr><th>Nama</th><th>Jadwal</th><th>Sesi</th><th>Istirahat</th><th>Status</th></tr></thead>
        <tbody>
          {board.rows.map(r=>{
            const m=STATUS_META[r.status]||STATUS_META.belum;
            const sesi=r.sessions.map(s=>`${hhmm(s.checkin_at)}–${s.checkout_at?hhmm(s.checkout_at):'…'}`).join(', ');
            return <tr key={r.staff_id}>
              <td>{r.name}</td>
              <td>{r.is_off?'Libur':(r.schedule||'-')}{r.override && <span title={r.note||'jadwal khusus hari ini'}> *</span>}</td>
              <td>{sesi||'–'}{r.outside_ip && <span title="Ada absen dari IP di luar hotel"> 🏠</span>}</td>
              <td>{r.on_break_since
                    ? <span className="ab-pill ab-break">sejak {hhmm(r.on_break_since)}</span>
                    : (r.breaks_min>0 ? <span>{r.breaks_min} mnt{r.over_break && <span className="ab-over" title="Melebihi batas maksimal istirahat"> ⚠</span>}</span> : '–')}</td>
              <td><span className={m.cls}>{m.label}</span></td>
            </tr>;
          })}
        </tbody>
      </table>
    </div>
  </div>;
}

/* ---------------- REKAP ---------------- */
function RekapView(){
  const now=new Date();
  const [ym,setYm]=useState(`${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}`);
  const [data,setData]=useState(null);
  useEffect(()=>{
    const [y,m]=ym.split('-');
    jGet(`/api/absen/rekap?year=${y}&month=${parseInt(m,10)}`).then(setData).catch(()=>setData(null));
  },[ym]);
  return <div className="card">
    <div className="card-h"><h3>Rekap Bulanan</h3>
      <input type="month" className="input" value={ym} onChange={e=>setYm(e.target.value)} style={{width:170}}/></div>
    {!data ? <div className="empty-state">Memuat…</div> :
    <table className="ab-table">
      <thead><tr><th>Nama</th><th>Hadir</th><th>Telat</th><th>Libur</th><th>Rata-rata masuk</th><th>Total jam kerja</th><th>Istirahat</th></tr></thead>
      <tbody>{data.rows.map(r=>(
        <tr key={r.staff_id}><td>{r.name}</td><td>{r.hadir}</td>
          <td>{r.telat>0?<span className="ab-pill ab-telat">{r.telat}</span>:0}</td>
          <td>{r.libur}</td><td>{r.avg_checkin||'–'}</td>
          <td>{r.total_kerja_min>0?fmtMin(r.total_kerja_min):'–'}</td>
          <td>{r.total_istirahat_min>0?fmtMin(r.total_istirahat_min):'–'}</td></tr>
      ))}</tbody>
    </table>}
  </div>;
}

/* ---------------- KELOLA (admin/manager) ---------------- */
function KelolaView(){
  const [staff,setStaff]=useState([]);
  const [ovs,setOvs]=useState([]);
  const [cfg,setCfg]=useState(null);
  const [msg,setMsg]=useState(null);
  const [newStaff,setNewStaff]=useState({name:'',default_start:'07:00',default_end:'15:00',default_start2:'',default_end2:'',pin:''});
  const [ovForm,setOvForm]=useState({staff_id:'',work_date:'',start_time:'',end_time:'',start_time2:'',end_time2:'',is_off:false,note:''});
  const loadAll=()=>{
    jGet('/api/absen/staff').then(setStaff);
    jGet('/api/absen/overrides').then(setOvs);
    jGet('/api/absen/config').then(setCfg);
  };
  useEffect(loadAll,[]);
  const flash=(ok,text)=>{setMsg({ok,text});setTimeout(()=>setMsg(null),4000)};
  const saveStaff=async(s,patch)=>{try{await jPatch(`/api/absen/staff/${s.id}`,patch);flash(true,`${s.name} tersimpan`);loadAll()}catch(e){flash(false,e.message)}};
  const setPinFor=async(s)=>{const p=prompt(`PIN baru untuk ${s.name} (4-6 digit):`);if(!p)return;
    if(!/^\d{4,6}$/.test(p)){flash(false,'PIN harus 4-6 digit angka');return}
    await saveStaff(s,{pin:p})};
  const addStaff=async()=>{try{
    const b={name:newStaff.name,default_start:newStaff.default_start,default_end:newStaff.default_end};
    if(newStaff.default_start2&&newStaff.default_end2){b.default_start2=newStaff.default_start2;b.default_end2=newStaff.default_end2}
    if(newStaff.pin) b.pin=newStaff.pin;
    await jPost('/api/absen/staff',b);setNewStaff({name:'',default_start:'07:00',default_end:'15:00',default_start2:'',default_end2:'',pin:''});flash(true,'Staff ditambahkan');loadAll();
  }catch(e){flash(false,e.message)}};
  const addOv=async()=>{try{
    const b={staff_id:parseInt(ovForm.staff_id,10),work_date:ovForm.work_date,is_off:ovForm.is_off,note:ovForm.note||null};
    if(!ovForm.is_off){
      b.start_time=ovForm.start_time;b.end_time=ovForm.end_time;
      if(ovForm.start_time2&&ovForm.end_time2){b.start_time2=ovForm.start_time2;b.end_time2=ovForm.end_time2}
    }
    await jPost('/api/absen/overrides',b);setOvForm({staff_id:'',work_date:'',start_time:'',end_time:'',start_time2:'',end_time2:'',is_off:false,note:''});flash(true,'Override tersimpan');loadAll();
  }catch(e){flash(false,e.message)}};
  const saveCfg=async()=>{try{await jPost('/api/absen/config',{tolerance_min:parseInt(cfg.tolerance_min,10),max_break_min:parseInt(cfg.max_break_min,10),hotel_ips:cfg.hotel_ips});flash(true,'Config tersimpan')}catch(e){flash(false,e.message)}};

  const timePair=(s,f1,f2,label)=>(
    <span className="ab-timepair" title={label}>
      <input type="time" className="input" defaultValue={s[f1]||''} style={{width:96}}
             onBlur={e=>{const v=e.target.value;if(v!==(s[f1]||''))saveStaff(s,{[f1]:v})}}/>
      {'–'}
      <input type="time" className="input" defaultValue={s[f2]||''} style={{width:96}}
             onBlur={e=>{const v=e.target.value;if(v!==(s[f2]||''))saveStaff(s,{[f2]:v})}}/>
    </span>
  );

  return <div>
    {msg && <div className={'ab-msg '+(msg.ok?'ok':'err')} style={{marginBottom:12}}>{msg.text}</div>}

    <div className="card" style={{marginBottom:16}}>
      <div className="card-h"><h3>Roster Staff</h3></div>
      <table className="ab-table">
        <thead><tr><th>Nama</th><th>Jam kerja 1</th><th>Jam kerja 2 (opsional)</th><th>PIN</th><th>Aktif</th></tr></thead>
        <tbody>{staff.map(s=>(
          <tr key={s.id} style={s.active?{}:{opacity:.5}}>
            <td>{s.name}</td>
            <td>{timePair(s,'default_start','default_end','Jam kerja 1')}</td>
            <td>{timePair(s,'default_start2','default_end2','Jam kerja 2')}
              {(s.default_start2||s.default_end2) &&
                <button className="btn btn-ghost btn-sm" title="Hapus jam kerja 2"
                        onClick={()=>saveStaff(s,{default_start2:'',default_end2:''})}>×</button>}
            </td>
            <td>{s.pin_set?'✓ diatur':<span className="ab-pill ab-telat">belum</span>}
              <button className="btn btn-ghost btn-sm" style={{marginLeft:6}} onClick={()=>setPinFor(s)}>Atur PIN</button></td>
            <td><input type="checkbox" checked={s.active} onChange={e=>saveStaff(s,{active:e.target.checked})}/></td>
          </tr>
        ))}</tbody>
      </table>
      <div className="ab-addrow">
        <input className="input" placeholder="Nama staff baru" value={newStaff.name} onChange={e=>setNewStaff({...newStaff,name:e.target.value})} style={{width:150}}/>
        <input type="time" className="input" value={newStaff.default_start} onChange={e=>setNewStaff({...newStaff,default_start:e.target.value})} style={{width:96}}/>
        <input type="time" className="input" value={newStaff.default_end} onChange={e=>setNewStaff({...newStaff,default_end:e.target.value})} style={{width:96}}/>
        <span className="muted" style={{fontSize:11}}>jam 2:</span>
        <input type="time" className="input" value={newStaff.default_start2} onChange={e=>setNewStaff({...newStaff,default_start2:e.target.value})} style={{width:96}}/>
        <input type="time" className="input" value={newStaff.default_end2} onChange={e=>setNewStaff({...newStaff,default_end2:e.target.value})} style={{width:96}}/>
        <input className="input" placeholder="PIN (opsional)" maxLength={6} value={newStaff.pin} onChange={e=>setNewStaff({...newStaff,pin:e.target.value.replace(/\D/g,'')})} style={{width:105}}/>
        <button className="btn btn-primary" disabled={newStaff.name.length<2} onClick={addStaff}>+ Tambah</button>
      </div>
    </div>

    <div className="card" style={{marginBottom:16}}>
      <div className="card-h"><h3>Override Tanggal (jadwal khusus / libur)</h3></div>
      <div className="ab-addrow">
        <select className="input" value={ovForm.staff_id} onChange={e=>setOvForm({...ovForm,staff_id:e.target.value})} style={{width:130}}>
          <option value="">— staff —</option>
          {staff.filter(s=>s.active).map(s=><option key={s.id} value={s.id}>{s.name}</option>)}
        </select>
        <input type="date" className="input" value={ovForm.work_date} onChange={e=>setOvForm({...ovForm,work_date:e.target.value})}/>
        <label style={{fontSize:12}}><input type="checkbox" checked={ovForm.is_off} onChange={e=>setOvForm({...ovForm,is_off:e.target.checked})}/> Libur</label>
        {!ovForm.is_off && <>
          <input type="time" className="input" value={ovForm.start_time} onChange={e=>setOvForm({...ovForm,start_time:e.target.value})} style={{width:96}}/>
          <input type="time" className="input" value={ovForm.end_time} onChange={e=>setOvForm({...ovForm,end_time:e.target.value})} style={{width:96}}/>
          <span className="muted" style={{fontSize:11}}>jam 2:</span>
          <input type="time" className="input" value={ovForm.start_time2} onChange={e=>setOvForm({...ovForm,start_time2:e.target.value})} style={{width:96}}/>
          <input type="time" className="input" value={ovForm.end_time2} onChange={e=>setOvForm({...ovForm,end_time2:e.target.value})} style={{width:96}}/>
        </>}
        <input className="input" placeholder="catatan" value={ovForm.note} onChange={e=>setOvForm({...ovForm,note:e.target.value})} style={{width:130}}/>
        <button className="btn btn-primary" disabled={!ovForm.staff_id||!ovForm.work_date||(!ovForm.is_off&&(!ovForm.start_time||!ovForm.end_time))} onClick={addOv}>Simpan</button>
      </div>
      {ovs.length===0 ? <div className="empty-state" style={{padding:14}}>Belum ada override 60 hari ke depan</div> :
      <table className="ab-table">
        <thead><tr><th>Tanggal</th><th>Staff</th><th>Jadwal</th><th>Catatan</th><th></th></tr></thead>
        <tbody>{ovs.map(o=>(
          <tr key={o.id}><td>{o.work_date}</td><td>{o.name}</td>
            <td>{o.is_off?<span className="ab-pill ab-libur">Libur</span>
                 :`${o.start_time}–${o.end_time}`+(o.start_time2?` & ${o.start_time2}–${o.end_time2}`:'')}</td>
            <td>{o.note||''}</td>
            <td><button className="btn btn-ghost btn-sm" onClick={async()=>{await jDel(`/api/absen/overrides/${o.id}`);loadAll()}}>Hapus</button></td></tr>
        ))}</tbody>
      </table>}
    </div>

    {cfg && <div className="card">
      <div className="card-h"><h3>Config</h3></div>
      <div className="ab-addrow">
        <label style={{fontSize:12}}>Toleransi telat (menit): <input type="number" className="input" min={0} max={180} value={cfg.tolerance_min} onChange={e=>setCfg({...cfg,tolerance_min:e.target.value})} style={{width:75}}/></label>
        <label style={{fontSize:12}}>Maks istirahat (menit/hari): <input type="number" className="input" min={0} max={480} value={cfg.max_break_min} onChange={e=>setCfg({...cfg,max_break_min:e.target.value})} style={{width:75}}/></label>
        <label style={{fontSize:12,flex:1}}>IP hotel (CSV IP/CIDR): <input className="input" placeholder="contoh: 192.168.33.0/24" value={cfg.hotel_ips} onChange={e=>setCfg({...cfg,hotel_ips:e.target.value})} style={{width:'100%',maxWidth:320}}/></label>
        <button className="btn btn-primary" onClick={saveCfg}>Simpan Config</button>
      </div>
      <div className="muted" style={{padding:'0 16px 14px',fontSize:11}}>Daftar IP kosong = penanda "di luar hotel" nonaktif. Silakan isi setelah observasi IP asli dari absen pertama.</div>
    </div>}
  </div>;
}

/* ---------------- SHELL ---------------- */
function AbsenTab({user}){
  const [sub,setSub]=useState('punch');
  const kelola = user && (user.role==='admin'||user.role==='manager');
  return <div>
    <div className="tabnav" style={{marginBottom:16,paddingLeft:0}}>
      <button className={'tab '+(sub==='punch'?'active':'')} onClick={()=>setSub('punch')}>Absen</button>
      <button className={'tab '+(sub==='rekap'?'active':'')} onClick={()=>setSub('rekap')}>Rekap</button>
      {kelola && <button className={'tab '+(sub==='kelola'?'active':'')} onClick={()=>setSub('kelola')}>Kelola</button>}
    </div>
    {sub==='punch' && <PunchBoard/>}
    {sub==='rekap' && <RekapView/>}
    {sub==='kelola' && kelola && <KelolaView/>}
  </div>;
}

window.AbsenTab = AbsenTab;
})();
