/* ============================================================
   Nuad Now — root App  (JSX)
   ============================================================ */
const { useState:useS, useEffect:useE, useCallback } = React;

/* ---------- BGM floating control ---------- */
function BGMControl() {
  const bgm = window.NuadBGM;
  const [muted, setMuted] = useS(false);
  const [vol, setVol]     = useS(0.28);
  const [open, setOpen]   = useS(false);
  const [ready, setReady] = useS(!!bgm);

  useE(() => { if (!bgm) return; setReady(true); bgm.start?.(); }, []);
  if (!ready) return null;

  const handleMute = () => { const n=!muted; setMuted(n); bgm.toggleMute(); };
  const handleVol  = (e) => {
    const v = Number(e.target.value);
    setVol(v); bgm.setVolume(v);
    if(v===0){setMuted(true);bgm.setMuted(true);}
    else if(muted){setMuted(false);bgm.setMuted(false);}
  };

  return (
    <div style={{position:'fixed',bottom:72,right:14,zIndex:50,display:'flex',flexDirection:'column',alignItems:'flex-end',gap:6}}>
      {open && (
        <div style={{background:'rgba(252,248,241,.96)',backdropFilter:'blur(10px)',border:'2.5px solid var(--ink)',borderRadius:'var(--r-lg)',padding:'12px 14px',display:'flex',flexDirection:'column',gap:8,boxShadow:'var(--shadow-card)',minWidth:140}}>
          <div style={{display:'flex',justifyContent:'space-between',alignItems:'center'}}>
            <span style={{fontFamily:'var(--font-display)',fontWeight:600,fontSize:'.82rem',color:'var(--ink-500)'}}>{t('bgm_vol')}</span>
            <span style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:'.82rem',color:'var(--accent)'}}>{muted?t('bgm_off'):Math.round(vol*100)+'%'}</span>
          </div>
          <input type="range" min="0" max="1" step="0.05" value={muted?0:vol} onChange={handleVol}
            style={{width:'100%',accentColor:'var(--accent)',cursor:'pointer',height:4,borderRadius:99}}/>
          <div style={{display:'flex',justifyContent:'space-between',fontSize:'.7rem',color:'var(--ink-300)',fontFamily:'var(--font-display)'}}>
            <span>🔈</span><span>🎵 {t('bgm_on')}</span><span>🔊</span>
          </div>
        </div>
      )}
      <button onClick={()=>setOpen(o=>!o)} onContextMenu={(e)=>{e.preventDefault();handleMute();}}
        title={muted?t('bgm_unmute'):t('bgm_mute')}
        style={{width:44,height:44,borderRadius:'50%',border:'2.5px solid var(--ink)',
          background:muted?'var(--cream-100)':'var(--accent)',color:muted?'var(--ink-300)':'#fff',
          display:'flex',alignItems:'center',justifyContent:'center',
          boxShadow:muted?'0 4px 0 var(--cream-300)':'0 4px 0 var(--accent-700)',
          cursor:'pointer',fontSize:'1.2rem',transition:'all .15s',flexShrink:0}}>
        {muted ? '🔇' : '🎵'}
      </button>
      {open && (
        <button onClick={handleMute} style={{background:'none',border:'none',cursor:'pointer',padding:0,
          fontFamily:'var(--font-display)',fontSize:'.72rem',color:'var(--ink-500)',textAlign:'center',textDecoration:'underline'}}>
          {muted ? t('bgm_unmute') : t('bgm_mute')}
        </button>
      )}
    </div>
  );
}

/* ============================================================ */
const emptyDraft = { dateKey:null, slot:null };

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#864A5E",
  "roundness": "ป่อง",
  "flowers": true,
  "bounce": true
}/*EDITMODE-END*/;

const ROUND_MAP = {
  'ป่อง':    {sm:'12px', md:'18px', lg:'26px', xl:'34px'},
  'กลาง':    {sm:'9px',  md:'13px', lg:'19px', xl:'25px'},
  'เหลี่ยม': {sm:'5px',  md:'8px',  lg:'12px', xl:'16px'},
};

function App(){
  /* ── language ── */
  const [lang, setLang] = useS('th');
  const changeLang = () => {
    const next = window.NN_LANG==='th' ? 'en' : 'th';
    window.NN_LANG = next;
    setLang(next);
  };

  /* ── tweaks ── */
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);

  /* ── app state ── */
  const [view,setView]       = useS(()=> DB?.getCurrentUser() ? 'app' : 'login');
  const [currentUser,setCUser]= useS(()=> DB?.getCurrentUser() || null);
  const [tab,setTab]         = useS('home');
  const [appLoading,setAppLoading]= useS(false);
  const [bookings,setBookings]= useS([]);
  const [allBookings,setAllBookings]= useS([]); // all users' bookings for slot counts
  const [openDaysSet,setOpenDaysSet]= useS(new Set()); // from DB
  const [draft,setDraft]     = useS(emptyDraft);
  const [bookingKey,setBKey] = useS(0);
  const [toasts,setToasts]   = useS([]);
  const [success,setSuccess] = useS(null);
  const [confetti,setConfetti]= useS(false);
  const [cancelT,setCancelT] = useS(null);
  const [surveyT,setSurveyT] = useS(null);
  const [notes,setNotes]     = useS([]);
  const [cfgVer,setCfgVer]   = useS(0);
  const [lbData,setLbData]   = useS(null);
  const [likedNoteIds,setLikedNoteIds]= useS([]); // note IDs liked by me
  const [canLike,setCanLike] = useS(true);
  const [myPoints,setMyPoints]= useS(0);

  /* ── use Supabase if configured, else fall back to demo ── */
  const useDB = window.SB && window.DB;

  /* points (computed from pointEvents state) */
  const [loginDays,setLoginDays] = useS(()=> useDB ? [] : NN.SEED_LOGIN_DAYS.slice());
  const [likedNotes,setLikedNotes]= useS(()=> useDB ? [] : NN.SEED_LIKED.slice());
  const [likeDays,setLikeDays]    = useS(()=> useDB ? [] : NN.SEED_LIKE_DAYS.slice());

  const pointState = { bookings, loginDays, likedNotes };
  const points     = useDB ? myPoints : NN.userPoints(pointState);
  const user       = currentUser || NN.USER;

  useE(()=>{
    const root=document.documentElement;
    root.style.setProperty('--accent', tw.accent);
    const r=ROUND_MAP[tw.roundness]||ROUND_MAP['ป่อง'];
    root.style.setProperty('--r-sm',r.sm); root.style.setProperty('--r-md',r.md);
    root.style.setProperty('--r-lg',r.lg); root.style.setProperty('--r-xl',r.xl);
    document.body.classList.toggle('no-flowers',!tw.flowers);
    document.body.classList.toggle('no-bounce',!tw.bounce);
  },[tw.accent,tw.roundness,tw.flowers,tw.bounce]);

  const toast = useCallback((msg,icon)=>{
    const id=Math.random().toString(36).slice(2);
    setToasts(x=>[...x,{id,msg,icon}]);
    setTimeout(()=> setToasts(x=>x.filter(z=>z.id!==id)), 2800);
  },[]);

  /* ── load all data from Supabase after login ── */
  const loadAppData = useCallback(async(emp) => {
    if(!useDB) return;
    setAppLoading(true);
    try {
      const today = NN.TODAY_KEY;
      const windowEnd = NN.ymd(NN.addDays(NN.parseKey(today), NN.BOOK_AHEAD));

      const [myBk, allBk, openDs, noteList, lb, ptEvents, likedToday] = await Promise.all([
        DB.loadMyBookings(emp.employee_id),
        DB.loadAllBookingsInWindow(today, windowEnd),
        DB.loadOpenDays(),
        DB.loadNotes(),
        DB.loadLeaderboard(),
        DB.loadPointEvents(emp.employee_id),
        DB.hasLikedToday(emp.employee_id),
      ]);

      setBookings(myBk);
      // build allBookings in the format NN expects (for bookedCount)
      setAllBookings(allBk.map(b=>({ dateKey:b.date_key, slot:b.slot_id, status:b.status })));
      setOpenDaysSet(openDs);
      setNotes(noteList);

      // mark me in leaderboard
      const lbWithMe = lb.map(r=>({...r, me: r.id===emp.employee_id}));
      if(!lbWithMe.find(r=>r.me)) lbWithMe.push({
        id:emp.employee_id, name:emp.nickname, nickname:emp.nickname,
        thai_firstname:emp.thai_firstname, thai_lastname:emp.thai_lastname,
        english_firstname:emp.english_firstname, english_lastname:emp.english_lastname,
        gender:emp.gender, dept:emp.dept, pts:0, me:true, rank:lbWithMe.length+1
      });
      lbWithMe.sort((a,b)=>b.pts-a.pts).forEach((r,i)=>r.rank=i+1);
      setLbData(lbWithMe);

      // compute my points
      const total = ptEvents.reduce((s,e)=>s+e.points,0);
      setMyPoints(total);

      // liked notes
      const myLikedIds = noteList.filter(n=>n.likedBy?.includes(emp.employee_id)).map(n=>n.id);
      setLikedNoteIds(myLikedIds);
      setCanLike(!likedToday);

      // apply open days to NN config
      NN.config.openDates = openDs;
      setCfgVer(v=>v+1);

    } catch(err) {
      console.error('loadAppData error:', err);
    } finally {
      setAppLoading(false);
    }
  }, [useDB]);

  /* load data if already logged in (page refresh) */
  useE(()=>{
    if(view==='app' && currentUser && useDB) loadAppData(currentUser);
  },[]);

  const login = async(emp) => {
    setCUser(emp);
    setView('app'); setTab('home');
    if(useDB){
      const alreadyIn = await DB.hasLoggedInToday(emp.employee_id);
      await loadAppData(emp);
      if(!alreadyIn){
        await DB.addPointEvent(emp.employee_id,'login',1,null);
        setMyPoints(p=>p+1);
        toast(t('ts_checkin'),'star');
      } else {
        toast(t('ts_welcome'),'heart');
      }
    } else {
      // demo mode
      const already=loginDays.includes(NN.TODAY_KEY);
      if(!already) setLoginDays(d=>[...d,NN.TODAY_KEY]);
      toast(already?t('ts_welcome'):t('ts_checkin'), already?'heart':'star');
    }
  };

  const logout=()=>{ DB?.logout(); setCUser(null); setBookings([]); setView('login'); };

  const startBooking=()=>{ setDraft(emptyDraft); setBKey(k=>k+1); setTab('book'); };

  const confirmBooking=async(d)=>{
    let b;
    if(useDB){
      const {booking,error}=await DB.createBooking(user.employee_id, d.dateKey, d.slot);
      if(error){ toast(error,'x'); return; }
      b=booking;
      await DB.addPointEvent(user.employee_id,'booking',5,b.id);
      setMyPoints(p=>p+5);
      // update slot count
      setAllBookings(prev=>[...prev,{dateKey:d.dateKey,slot:d.slot,status:'confirmed'}]);
    } else {
      b={ id:'bk_'+Math.random().toString(36).slice(2,8), dateKey:d.dateKey, slot:d.slot,
          status:'confirmed', attended:false, surveyDone:false, created:Date.now() };
    }
    setBookings(list=>[...list,b]);
    setSuccess(b); setConfetti(true);
    setTimeout(()=>setConfetti(false),2600);
    toast(t('ts_booked'),'star');
  };
  const afterSuccess=()=>{ setSuccess(null); setDraft(emptyDraft); setTab('mine'); };

  const doCancel=async()=>{
    if(!cancelT) return;
    const bk=cancelT;
    setCancelT(null); // ปิด modal ทันที ป้องกันกดซ้ำ
    if(useDB){
      await DB.cancelBooking(bk.id);
      await DB.addPointEvent(user.employee_id,'cancel',-5,bk.id);
      setMyPoints(p=>p-5);
      setAllBookings(prev=>prev.filter(b=>!(b.dateKey===bk.dateKey&&b.slot===bk.slot&&b.status==='confirmed')));
    }
    setBookings(list=>list.filter(b=>b.id!==bk.id));
    toast(t('ts_cancelled'),'x');
  };

  const submitSurvey=async(b)=>{
    if(useDB){
      const {error}=await DB.submitSurvey(b.id, user.employee_id, b._rating||5, b._comment||'');
      if(error){ toast(error,'x'); return; }
      await DB.addPointEvent(user.employee_id,'survey',5,b.id);
      setMyPoints(p=>p+5);
    }
    setBookings(list=>list.map(x=> x.id===b.id?{...x,surveyDone:true}:x));
    setSurveyT(null);
    setConfetti(true); setTimeout(()=>setConfetti(false),2200);
    toast(t('ts_survey'),'star');
  };

  const likeNote=async(note)=>{
    if(likedNoteIds.includes(note.id)) return;
    if(!canLike){ toast(t('ts_like_full'),'bell'); return; }
    if(useDB){
      const {error}=await DB.likeNote(note.id, user.employee_id);
      if(error){ toast(error,'x'); return; }
      await DB.addPointEvent(user.employee_id,'like',1,note.id);
      setMyPoints(p=>p+1);
      setCanLike(false);
    } else {
      if(!NN.canLikeToday(likeDays)){ toast(t('ts_like_full'),'bell'); return; }
      setLikedNotes(x=>[...x,note.id]);
      setLikeDays(x=>[...x,NN.TODAY_KEY]);
    }
    setNotes(list=>list.map(n=> n.id===note.id?{...n,likes:n.likes+1}:n));
    setLikedNoteIds(x=>[...x,note.id]);
    toast(t('ts_liked'),'heart');
  };

  const navTo=(target)=> target==='book'?startBooking():setTab(target);
  const removeNote=async(noteId)=>{
    if(useDB){
      const {error}=await DB.deleteNote(noteId, user.employee_id);
      if(error){ toast(error,'x'); return; }
    }
    setNotes(list=>list.filter(n=>n.id!==noteId));
    toast('ลบโพสต์อิทแล้ว','x');
  };

  const addNote=async(n)=>{
    if(useDB){
      const fullName=`${user.thai_firstname||''} ${user.thai_lastname||''}`.trim()||user.nickname||user.name;
      const {note,error}=await DB.createNote(user.employee_id, user.nickname||user.name, fullName, n.text, n.color, n.tilt);
      if(error){ toast(error,'x'); return; }
      setNotes(list=>[note,...list]);
    } else {
      setNotes(list=>[n,...list]);
    }
    toast(t('ts_posted'),'check');
  };
  const bumpCfg=()=> setCfgVer(v=>v+1);

  const panel = (
    <TweaksPanel title="ปรับแต่ง Nuad Now">
      <TweakSection label="สีหลักของแบรนด์"/>
      <TweakColor label="สีหลัก" value={tw.accent}
        options={['#864A5E','#6E8F66','#B98740','#4E8A86','#A65A6E']}
        onChange={v=>setTweak('accent',v)}/>
      <TweakSection label="ความน่ารัก"/>
      <TweakRadio label="ความโค้งมุม" value={tw.roundness}
        options={['ป่อง','กลาง','เหลี่ยม']} onChange={v=>setTweak('roundness',v)}/>
      <TweakToggle label="ดอกไม้พื้นหลัง" value={tw.flowers} onChange={v=>setTweak('flowers',v)}/>
      <TweakToggle label="มาสคอตเด้งดึ๋ง" value={tw.bounce} onChange={v=>setTweak('bounce',v)}/>
    </TweaksPanel>
  );

  if(view==='login') return (
    <><LoginScreen onLogin={login} lang={lang} onLangChange={changeLang}/><Toasts items={toasts}/>{panel}<BGMControl/></>
  );

  return (
    <>
      <Shell tab={tab} setTab={navTo} user={user} points={points} onLogout={logout} onLangChange={changeLang}>
        {tab==='home'  && <Home user={user} bookings={bookings} allBookings={useDB?allBookings:null} points={points} pointState={pointState}
          onBook={startBooking} onGoMine={()=>setTab('mine')} onGoRank={()=>setTab('rank')} onGoBoard={()=>setTab('board')} onSurvey={setSurveyT}/>}
        {tab==='book'  && <BookingFlow key={bookingKey} bookings={bookings} allBookings={useDB?allBookings:null} draft={draft} setDraft={setDraft}
          onConfirm={confirmBooking} onExit={()=>setTab('home')}/>}
        {tab==='mine'  && <MyBookings bookings={bookings} onCancel={setCancelT} onSurvey={setSurveyT} onBook={startBooking}/>}
        {tab==='rank'  && <Ranking pointState={pointState} points={points} lbData={useDB?lbData:null}/>}
        {tab==='board' && <Board notes={notes} user={user} onAdd={addNote} onLike={likeNote} onDelete={removeNote} likedNotes={likedNotes} canLike={canLike}/>}
        {tab==='admin' && <AdminDays bookings={bookings} cfgVer={cfgVer} onChange={bumpCfg}/>}
      </Shell>

      <Confetti show={confetti}/>
      <Toasts items={toasts}/>

      {success && <SuccessModal b={success} onClose={afterSuccess}/>}
      {surveyT  && <SurveyModal b={surveyT}  onClose={()=>setSurveyT(null)} onSubmit={submitSurvey}/>}

      {cancelT &&
        <div className="overlay" onClick={()=>setCancelT(null)}>
          <div className="modal" onClick={e=>e.stopPropagation()} style={{maxWidth:400}}>
            <h2 style={{fontSize:'1.4rem'}}>{t('cx_title')}</h2>
            <p className="muted" style={{margin:'8px 0 6px'}}>
              {t('bk_service')} · {NN.fmtDateLong(cancelT.dateKey)} {NN.slotLabel(cancelT.slot)}{window.NN_LANG==='th'?' น.':''}
            </p>
            <p style={{color:'var(--bad)',fontSize:'.88rem',margin:'0 0 18px'}}>{t('cx_warn')}</p>
            <div className="row" style={{gap:10,justifyContent:'center'}}>
              <button className="btn secondary" onClick={()=>setCancelT(null)}>{t('cx_keep')}</button>
              <button className="btn danger" onClick={doCancel}>{t('cx_yes')}</button>
            </div>
          </div>
        </div>}
      {panel}
      <BGMControl/>
    </>
  );
}

/* ---------- Success modal ---------- */
function SuccessModal({b, onClose}){
  const lang=window.NN_LANG||'th';
  const timeStr=NN.slotLabel(b.slot)+(lang==='en'?'':' น.');
  return (
    <div className="overlay" onClick={onClose}>
      <div className="modal" onClick={e=>e.stopPropagation()}>
        <div style={{display:'flex',justifyContent:'center',marginTop:-90,marginBottom:6}}><Mascot w={150}/></div>
        <div className="chip sage" style={{margin:'0 auto 10px'}}><Icon name="check" size={16}/> {t('ok_chip')}</div>
        <h2 style={{fontSize:'1.6rem'}}>{t('ok_title')}</h2>
        <p className="muted" style={{margin:'8px 0 16px'}}>{t('ok_sub')}</p>
        <div className="card flat pad" style={{textAlign:'left'}}>
          <div className="kv" style={{padding:'5px 0'}}><span className="k">{t('ok_svc')}</span><span className="v">{t('bk_service')}</span></div>
          <div className="kv" style={{padding:'5px 0'}}><span className="k">{t('ok_dt')}</span><span className="v">{NN.fmtDateShort(b.dateKey)} · {timeStr}</span></div>
          <div className="kv" style={{padding:'5px 0'}}><span className="k">{t('ok_pts')}</span><span className="v" style={{color:'var(--gold-600)'}}>+5 {t('pts')} ⭐</span></div>
        </div>
        <button className="btn lg block" style={{marginTop:18}} onClick={onClose}>{t('ok_btn')} <Icon name="chevR" size={18}/></button>
      </div>
    </div>
  );
}

/* ---------- Survey modal ---------- */
function SurveyModal({b, onClose, onSubmit}){
  const [rating,setRating]=useS(5);
  const [text,setText]=useS('');
  const lang=window.NN_LANG||'th';
  const labels=TL.sv_labels_th[lang]||TL.sv_labels_th.th;
  const timeStr=NN.slotLabel(b.slot)+(lang==='en'?'':' น.');
  return (
    <div className="overlay" onClick={onClose}>
      <div className="modal" onClick={e=>e.stopPropagation()} style={{maxWidth:480}}>
        <div style={{display:'flex',justifyContent:'center',marginTop:-86,marginBottom:4}}><Mascot w={140}/></div>
        <h2 style={{fontSize:'1.5rem'}}>{t('sv_title')}</h2>
        <p className="muted" style={{margin:'6px 0 14px'}}>{NN.fmtDateLong(b.dateKey)} · {timeStr}</p>
        <div className="row" style={{justifyContent:'center',gap:6,marginBottom:4}}>
          {[1,2,3,4,5].map(n=>(
            <button key={n} onClick={()=>setRating(n)} style={{background:'none',border:'none',padding:2,cursor:'pointer',
              color:n<=rating?'var(--gold)':'var(--cream-300)',transition:'transform .1s',transform:n<=rating?'scale(1.05)':'none'}}>
              <Glyph kind="spark" size={38} color="currentColor"/>
            </button>
          ))}
        </div>
        <div className="center" style={{fontFamily:'var(--font-display)',fontWeight:600,color:'var(--gold-600)',marginBottom:16,minHeight:'1.2em'}}>{labels[rating]}</div>
        <div className="field" style={{textAlign:'left',marginBottom:18}}>
          <label>{t('sv_comment')} <span className="muted" style={{fontWeight:400}}>{t('sv_optional')}</span></label>
          <textarea className="input" value={text} onChange={e=>setText(e.target.value)} maxLength={200}
            placeholder={t('sv_ph')} style={{resize:'none',minHeight:88,fontFamily:'var(--font-body)'}}/>
        </div>
        <button className="btn lg block gold" onClick={()=>onSubmit(b,rating,text)}><Icon name="star" size={18}/> {t('sv_btn')}</button>
      </div>
    </div>
  );
}

Object.assign(window, { App, SuccessModal, SurveyModal });
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
