// ============================================================
// store.jsx — state: overrides + leaves + requests (standin/swap)
// ============================================================
const { createContext, useContext, useState: useSt, useCallback: useCb, useEffect: useEff } = React;
const StoreCtx = createContext(null);
const SK = 'muen_v3';
const CLOUD = 'https://muen-charoen.pages.dev/api/store';

async function fetchCloud(){
  try {
    const r = await fetch(CLOUD);
    if(r.ok){ const d=await r.json(); if(d&&typeof d==='object'&&Object.keys(d).length>0) return d; }
  } catch{}
  return null;
}
async function pushCloud(data){
  try { await fetch(CLOUD,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)}); } catch{}
}

function dayKey(date, staffId){
  return `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2,'0')}-${String(date.getDate()).padStart(2,'0')}_${staffId}`;
}
function strToDate(s){ const [y,m,d]=s.split('_')[0].split('-').map(Number); return new Date(y,m-1,d); }
function dateStr(date){ return `${date.getFullYear()}-${String(date.getMonth()+1).padStart(2,'0')}-${String(date.getDate()).padStart(2,'0')}`; }
function normStore(s){ if(!s.overrides)s.overrides={}; if(!s.leaves)s.leaves={}; if(!s.ots)s.ots={}; if(!s.requests)s.requests={}; if(!s.transfers)s.transfers={}; if(!s.audit)s.audit=[]; return s; }
function loadS(){ try{ return normStore({ overrides:{},leaves:{},ots:{},requests:{},transfers:{},audit:[], ...JSON.parse(localStorage.getItem(SK)||'{}')}); }catch{ return normStore({}); } }

function baseAssignMap(date){
  const w = weekIndex(date), map = {};
  STAFF.forEach((s,i)=>{ if(s.offDays.includes(date.getDay())){map[s.id]='off';return;} const sl=SLOTS[(i+w)%SLOTS.length]; map[s.id]={b:sl.b,s:sl.s}; });
  return map;
}

function StoreProvider({ children, currentUserId }){
  const [store, setS] = useSt(loadS);

  useEff(()=>{
    fetchCloud().then(cloud=>{
      if(cloud){
        setS(s=>{
          const useCloud = (cloud._ts||0) >= (s._ts||0);
          if(useCloud){ const n=normStore({overrides:{},leaves:{},ots:{},requests:{},transfers:{},audit:[],...cloud}); try{localStorage.setItem(SK,JSON.stringify(n));}catch{} return n; }
          return s;
        });
      }
    });
  },[]);

  const upd = useCb(fn=>{ setS(p=>{ const n=fn(structuredClone(p)); n._ts=Date.now(); try{localStorage.setItem(SK,JSON.stringify(n));}catch{} pushCloud(n); return n; }); },[]);

  const setOverride  = useCb((date,sid,asgn)=>upd(s=>{
    const k=dayKey(date,sid);
    const before=s.overrides[k]!==undefined?s.overrides[k]:null;
    s.overrides[k]=asgn;
    (s.audit||(s.audit=[])).push({who:currentUserId,ds:dateStr(date),staffId:sid,before,after:asgn,at:Date.now()});
    return s;
  }),[upd,currentUserId]);
  const clearOverride= useCb((date,sid)=>upd(s=>{
    const k=dayKey(date,sid);
    const before=s.overrides[k]!==undefined?s.overrides[k]:null;
    delete s.overrides[k];
    if(before!==null)(s.audit||(s.audit=[])).push({who:currentUserId,ds:dateStr(date),staffId:sid,before,after:null,at:Date.now()});
    return s;
  }),[upd,currentUserId]);

  const requestLeave = useCb((date,sid,note,ltype)=>upd(s=>{s.leaves[dayKey(date,sid)]={staffId:sid,ds:dateStr(date),status:'pending',note,ltype:ltype||'emergency',at:Date.now()};return s;}),[upd]);
  const requestAdvanceLeaves = useCb((dates,sid,note)=>upd(s=>{ dates.forEach(d=>{ s.leaves[dayKey(d,sid)]={staffId:sid,ds:dateStr(d),status:'pending',note:note||'',ltype:'advance',at:Date.now()}; }); return s; }),[upd]);
  const updateLeave  = useCb((date,sid,status)=>upd(s=>{const k=dayKey(date,sid);if(s.leaves[k])s.leaves[k].status=status;return s;}),[upd]);
  const cancelLeave  = useCb((date,sid)=>upd(s=>{delete s.leaves[dayKey(date,sid)];return s;}),[upd]);

  const requestOT    = useCb((date,sid,note,hours)=>upd(s=>{s.ots[dayKey(date,sid)]={staffId:sid,ds:dateStr(date),status:'pending',note,hours:hours||0,at:Date.now()};return s;}),[upd]);
  const updateOT     = useCb((date,sid,status)=>upd(s=>{const k=dayKey(date,sid);if(s.ots[k])s.ots[k].status=status;return s;}),[upd]);
  const cancelOT     = useCb((date,sid)=>upd(s=>{delete s.ots[dayKey(date,sid)];return s;}),[upd]);

  const requestTransfer = useCb((date,sid,toBranch,time,fuel)=>upd(s=>{s.transfers[dayKey(date,sid)]={staffId:sid,ds:dateStr(date),toBranch,time,fuel:fuel||60,status:'pending',at:Date.now()};return s;}),[upd]);
  const updateTransfer  = useCb((date,sid,status)=>upd(s=>{const k=dayKey(date,sid);if(s.transfers[k])s.transfers[k].status=status;return s;}),[upd]);
  const cancelTransfer  = useCb((date,sid)=>upd(s=>{delete s.transfers[dayKey(date,sid)];return s;}),[upd]);

  const newId = ()=>`r${Date.now()}${Math.random().toString(36).slice(2,5)}`;
  const sendRequest = useCb((type,fromSid,targetSid,targetDate,offerDate)=>upd(s=>{ s.requests[newId()]={type,fromSid,targetSid,targetDs:dateStr(targetDate),offerDs:offerDate?dateStr(offerDate):null,status:'pending',at:Date.now()}; return s; }),[upd]);
  const cancelRequest = useCb((id)=>upd(s=>{ delete s.requests[id]; return s; }),[upd]);

  const updateRequest = useCb((id,status)=>upd(s=>{
    const r=s.requests[id]; if(!r)return s;
    r.status=status;
    if(status==='accepted'){
      const tDate=new Date(r.targetDs+'T00:00:00'), fromMap=baseAssignMap(tDate);
      if(r.type==='standin'){
        // requester takes target's slot on targetDate
        s.overrides[dayKey(tDate,r.fromSid)]=fromMap[r.targetSid]||'off';
      } else if(r.type==='swap' && r.offerDs){
        const oDate=new Date(r.offerDs+'T00:00:00'), oMap=baseAssignMap(oDate);
        // swap: from gets target's slot on targetDate; target gets from's slot on offerDate
        s.overrides[dayKey(tDate,r.fromSid)]=fromMap[r.targetSid]||'off';
        s.overrides[dayKey(oDate,r.targetSid)]=oMap[r.fromSid]||'off';
      }
    }
    return s;
  }),[upd]);

  const pendingOTsAdmin      = ()=>Object.values(store.ots).filter(o=>o.status==='pending');
  const pendingLeavesAdmin   = ()=>Object.values(store.leaves).filter(l=>l.status==='pending');
  const pendingTransfersAdmin= ()=>Object.values(store.transfers||{}).filter(t=>t.status==='pending');
  const pendingRequestsFor = (sid)=>Object.entries(store.requests).filter(([,r])=>r.targetSid===sid&&r.status==='pending').map(([id,r])=>({...r,id}));
  const myPendingRequests  = (sid)=>Object.entries(store.requests).filter(([,r])=>r.fromSid===sid&&r.status==='pending').map(([id,r])=>({...r,id}));

  const ctx={ store,setOverride,clearOverride,requestLeave,requestAdvanceLeaves,updateLeave,cancelLeave,
    requestOT,updateOT,cancelOT,
    requestTransfer,updateTransfer,cancelTransfer,
    sendRequest,updateRequest,cancelRequest,
    pendingOTsAdmin,pendingLeavesAdmin,pendingTransfersAdmin,pendingRequestsFor,myPendingRequests,
    dayKey,strToDate,dateStr,baseAssignMap };
  return React.createElement(StoreCtx.Provider,{value:ctx},children);
}
function useStore(){ return useContext(StoreCtx); }
Object.assign(window,{StoreCtx,StoreProvider,useStore,dayKey,strToDate,dateStr,baseAssignMap});
