// Student · Messages — messenger-style support thread with the coaching team.
// Exposes window.StudentChat({ client, session, name }).
(function(){
const { useState, useEffect, useRef } = React;
const { fmtTime, dayLabel, fmtFull, startPresenceLoop, isOnline, relTime } = window.ChatCommon;
const { ConfirmModal, Ticks, ReactionBar, ReactPicker, TypingDots } = window.ChatUI;

function StudentChat({ client, session, name }){
  const meEmail=(session.user.email||'').toLowerCase();
  const thread='support:'+meEmail;
  const [msgs,setMsgs]=useState([]); const [reactions,setReactions]=useState({}); const [reads,setReads]=useState([]);
  const [unread,setUnread]=useState(0); const [coachOnline,setCoachOnline]=useState(false);
  const [otherTyping,setOtherTyping]=useState(false);
  const [body,setBody]=useState(''); const [err,setErr]=useState(''); const [sending,setSending]=useState(false); const [open,setOpen]=useState(false);
  const [staffOnline,setStaffOnline]=useState(false);
  const [editId,setEditId]=useState(null); const [editText,setEditText]=useState('');
  const [replyTo,setReplyTo]=useState(null); const [pickerFor,setPickerFor]=useState(null); const [confirm,setConfirm]=useState(null);
  const scroller=useRef(null); const lastTypingSent=useRef(0);
  const myName=(name&&name.split(' ')[0])||meEmail.split('@')[0];

  useEffect(()=>{ if(document.getElementById('cg-chat-css')) return; const s=document.createElement('style'); s.id='cg-chat-css';
    s.textContent='.cg-typedot{width:5px;height:5px;border-radius:50%;background:rgba(26,19,3,.55);animation:cgTyping 1s infinite ease-in-out}.cg-typedot:nth-child(2){animation-delay:.15s}.cg-typedot:nth-child(3){animation-delay:.3s}@keyframes cgTyping{0%,60%,100%{opacity:.35;transform:translateY(0)}30%{opacity:1;transform:translateY(-2px)}}.cg-msg-row:hover .cg-msg-actions{opacity:1}.cg-msg-actions{opacity:0;transition:opacity .15s}@media(max-width:600px){.cg-msg-actions{opacity:1}}';
    document.head.appendChild(s);
  },[]);
  useEffect(()=>{ const iv=startPresenceLoop(client, meEmail); return ()=>clearInterval(iv); },[]);

  async function load(){ const { data, error } = await client.from('chat_messages').select('*').eq('thread_key',thread).order('created_at',{ascending:true});
    if(error){ setErr(error.message); return; } setErr(''); setMsgs((data||[]).filter(m=>!m.staff_only));
    const { data:rx } = await client.from('chat_reactions').select('*').eq('thread_key',thread);
    const rmap={}; (rx||[]).forEach(r=>{ (rmap[r.message_id]=rmap[r.message_id]||[]).push(r); }); setReactions(rmap);
    const { data:rd } = await client.from('chat_reads').select('*').eq('thread_key',thread); setReads(rd||[]);
  }
  async function markRead(){ await client.from('chat_reads').upsert({thread_key:thread,reader_email:meEmail,last_read_at:new Date().toISOString()}); }
  useEffect(()=>{ load(); const iv=setInterval(load, open?3500:15000); return ()=>clearInterval(iv); },[open]);
  useEffect(()=>{ if(open){ markRead(); } },[open,msgs.length]);
  useEffect(()=>{ if(open&&scroller.current) scroller.current.scrollTop=scroller.current.scrollHeight; },[msgs,open,otherTyping]);

  // unread badge on the collapsed header
  useEffect(()=>{ let stop=false; async function chk(){ if(stop||open) return; const { data:rd } = await client.from('chat_reads').select('*').eq('thread_key',thread).eq('reader_email',meEmail);
      const last = rd&&rd[0]?rd[0].last_read_at:null;
      const n=(msgs||[]).filter(m=>!m.deleted && m.sender_email.toLowerCase()!==meEmail && (!last||new Date(m.created_at)>new Date(last))).length;
      setUnread(n); }
    chk(); const iv=setInterval(chk,8000); return ()=>{ stop=true; clearInterval(iv); }; },[msgs,open]);

  // staff presence (any staff online) + typing
  useEffect(()=>{ let stop=false; async function poll(){ if(stop) return;
      const { data:t } = await client.from('chat_typing').select('*').eq('thread_key',thread);
      const now=Date.now(); setOtherTyping((t||[]).some(x=>x.sender_email.toLowerCase()!==meEmail && (now-new Date(x.updated_at).getTime())<6000));
    } poll(); const iv=setInterval(poll,2500); return ()=>{ stop=true; clearInterval(iv); }; },[open]);
  function pingTyping(){ const now=Date.now(); if(now-lastTypingSent.current<2500) return; lastTypingSent.current=now;
    client.from('chat_typing').upsert({thread_key:thread,sender_email:meEmail,updated_at:new Date().toISOString()}).then(()=>{}); }

  // staff presence (any coach/admin who has messaged you or is generally online)
  useEffect(()=>{ let stop=false; async function poll(){ if(stop) return; const { data } = await client.from('chat_presence').select('*');
      const now=Date.now(); setStaffOnline((data||[]).some(p=>p.email.toLowerCase()!==meEmail && (now-new Date(p.last_seen).getTime())<45000)); }
    poll(); const iv=setInterval(poll,15000); return ()=>{ stop=true; clearInterval(iv); }; },[]);

  async function send(){ const text=body.trim(); if(!text||sending) return; setSending(true); setErr('');
    const row={ thread_key:thread, sender_email:meEmail, sender_name:myName, sender_role:'student', body:text, reply_to_id:replyTo?replyTo.id:null };
    setBody(''); setReplyTo(null);
    const { error } = await client.from('chat_messages').insert(row);
    if(error){ setErr(error.message); setBody(text); } else { load(); markRead(); }
    setSending(false);
  }
  async function toggleReaction(m,emoji){
    const mine=(reactions[m.id]||[]).find(r=>r.reactor_email.toLowerCase()===meEmail);
    if(mine && mine.emoji===emoji){ await client.from('chat_reactions').delete().eq('message_id',m.id).eq('reactor_email',meEmail); }
    else { await client.from('chat_reactions').upsert({message_id:m.id,thread_key:thread,reactor_email:meEmail,emoji}); }
    setPickerFor(null); load();
  }
  function del(m){ setConfirm({ title:'Delete this message?', body:'It will show as "message deleted" for your coach too.', run: async()=>{ const { error } = await client.from('chat_messages').update({deleted:true}).eq('id',m.id); if(error) setErr(error.message); else load(); setConfirm(null); } }); }
  function startEdit(m){ setEditId(m.id); setEditText(m.body||''); }
  async function saveEdit(m){ const t=editText.trim(); if(!t){ setEditId(null); return; } const { error } = await client.from('chat_messages').update({body:t, edited_at:new Date().toISOString()}).eq('id',m.id); if(error){ setErr(error.message); } else { setEditId(null); setEditText(''); load(); } }

  const otherReadAt = (()=>{ const others=reads.filter(r=>r.reader_email.toLowerCase()!==meEmail); if(!others.length) return null; return others.map(r=>new Date(r.last_read_at).getTime()).sort((a,b)=>b-a)[0]; })();
  let lastDay=null;

  return <div style={{marginBottom:34,border:'1px solid var(--border-gold)',borderRadius:'var(--radius)',overflow:'hidden',background:'linear-gradient(165deg,var(--surface-2),var(--surface))',boxShadow:open?'var(--shadow)':'0 0 0 1px rgba(212,175,55,.06)'}}>
    {confirm && <ConfirmModal title={confirm.title} body={confirm.body} confirmLabel="Delete" onCancel={()=>setConfirm(null)} onConfirm={confirm.run}/>}
    <button onClick={()=>setOpen(o=>!o)} style={{width:'100%',display:'flex',alignItems:'center',justifyContent:'space-between',gap:12,padding:'16px 20px',cursor:'pointer',color:'#1a1303',border:'none',background:'linear-gradient(115deg,var(--gold-2) 0%,var(--gold) 60%,#c79a2e 100%)'}}>
      <div style={{display:'flex',alignItems:'center',gap:14}}>
        <span style={{position:'relative',width:46,height:46,borderRadius:'50%',flexShrink:0,display:'grid',placeItems:'center',background:'radial-gradient(circle at 50% 35%, #142046, var(--navy-950))',boxShadow:'0 3px 12px rgba(0,0,0,.35), inset 0 0 0 1px rgba(245,217,122,.5)'}}>
          <Lotus/>
          {!!unread && <span style={{position:'absolute',top:-4,right:-4,minWidth:19,height:19,padding:'0 5px',borderRadius:999,background:'var(--red)',color:'#fff',fontSize:'.66rem',fontWeight:700,display:'grid',placeItems:'center',fontFamily:'var(--font-mono)',border:'2px solid var(--navy-950)'}}>{unread>9?'9+':unread}</span>}
        </span>
        <div style={{textAlign:'left'}}>
          <div style={{fontWeight:700,fontSize:'1.08rem',letterSpacing:'.01em'}}>Messages</div>
          <div style={{fontSize:'.8rem',color:'rgba(26,19,3,.72)',display:'flex',alignItems:'center',gap:6}}>{staffOnline && <span style={{width:7,height:7,borderRadius:'50%',background:'#1c7a3e',flexShrink:0}}/>}{staffOnline?'Your coaching team is online':'Chat privately with your coach & the team'}</div>
        </div>
      </div>
      <span style={{fontFamily:'var(--font-mono)',fontSize:'.78rem',fontWeight:600,color:'rgba(26,19,3,.82)',whiteSpace:'nowrap'}}>{open?'Hide ▲':(unread?unread+' new ▾':(msgs.length?msgs.length+' ▾':'Open ▾'))}</span>
    </button>
    {open && <div style={{borderTop:'1px solid var(--border)'}}>
      <div ref={scroller} style={{maxHeight:'62vh',minHeight:220,overflowY:'auto',padding:'16px 20px',display:'flex',flexDirection:'column',gap:4}}>
        {msgs.length===0 && <div style={{margin:'20px auto',color:'var(--ink-faint)',fontSize:'.9rem',textAlign:'center'}}>No messages yet.<br/>Ask your coach anything 👋</div>}
        {msgs.map(m=>{ const mine=(m.sender_email||'').toLowerCase()===meEmail; const editing=editId===m.id;
          const thisDay=dayLabel(m.created_at); const showDay=thisDay!==lastDay; lastDay=thisDay;
          const seen = mine && !!otherReadAt && otherReadAt>=new Date(m.created_at).getTime();
          const quoted = m.reply_to_id ? msgs.find(x=>x.id===m.reply_to_id) : null;
          const rx = reactions[m.id]||[]; const counts={}; rx.forEach(r=>counts[r.emoji]=(counts[r.emoji]||0)+1); const mineReact=rx.find(r=>r.reactor_email.toLowerCase()===meEmail);
          return <React.Fragment key={m.id}>
            {showDay && <div style={{textAlign:'center',margin:'10px 0 6px'}}><span style={{fontSize:'.68rem',fontFamily:'var(--font-mono)',color:'var(--ink-faint)',background:'var(--surface)',border:'1px solid var(--border)',borderRadius:999,padding:'3px 12px'}}>{thisDay}</span></div>}
            <div className="cg-msg-row" style={{alignSelf:mine?'flex-end':'flex-start',maxWidth:'82%',position:'relative',marginBottom:6}}>
              {!mine && <div style={{fontSize:'.7rem',color:'var(--gold-2)',fontFamily:'var(--font-mono)',marginBottom:3,marginLeft:2}}>{m.sender_name||'Coach'}{m.sender_role&&m.sender_role!=='student'?' · '+m.sender_role:''}</div>}
              {editing
                ? <div style={{display:'flex',flexDirection:'column',gap:6}}>
                    <textarea value={editText} onChange={e=>setEditText(e.target.value)} rows={2} style={{resize:'none',padding:'9px 12px',borderRadius:12,background:'var(--navy-950)',border:'1px solid var(--border-gold)',color:'var(--ink)',fontFamily:'var(--font-body)',fontSize:'.9rem',minWidth:200}}/>
                    <div style={{display:'flex',gap:12,justifyContent:'flex-end',fontSize:'.72rem'}}><span onClick={()=>{setEditId(null);setEditText('');}} style={{cursor:'pointer',color:'var(--ink-faint)'}}>Cancel</span><span onClick={()=>saveEdit(m)} style={{cursor:'pointer',color:'var(--gold-2)',fontWeight:600}}>Save</span></div>
                  </div>
                : <div style={{position:'relative'}}>
                    {quoted && <div style={{fontSize:'.76rem',color:'var(--ink-faint)',background:'var(--surface)',borderLeft:'2px solid var(--border-gold)',borderRadius:'8px 8px 0 0',padding:'5px 10px',opacity:.85}}>{(quoted.sender_name||'')+': '}{(quoted.deleted?'message deleted':quoted.body||'').slice(0,80)}</div>}
                    <div style={{padding:'10px 14px',borderRadius:quoted?(mine?'0 3px 3px 13px':'0 13px 13px 3px'):(mine?'13px 13px 3px 13px':'13px 13px 13px 3px'),background:m.deleted?'transparent':(mine?'linear-gradient(135deg,var(--gold-2),var(--gold))':'var(--surface)'),color:m.deleted?'var(--ink-faint)':(mine?'#1a1303':'var(--ink)'),border:m.deleted?'1px dashed var(--border)':(mine?'none':'1px solid var(--border)'),fontStyle:m.deleted?'italic':'normal',fontSize:'.92rem',lineHeight:1.48,whiteSpace:'pre-wrap',wordBreak:'break-word'}}>{m.deleted?'message deleted':m.body}</div>
                  </div>}
              <ReactionBar mine={mine} active={mineReact?mineReact.emoji:null} counts={Object.keys(counts).length?counts:null} onToggle={(e)=>toggleReaction(m,e)} />
              <div style={{fontSize:'.66rem',color:'var(--ink-faint)',fontFamily:'var(--font-mono)',marginTop:3,textAlign:mine?'right':'left',display:'flex',gap:6,justifyContent:mine?'flex-end':'flex-start',alignItems:'center'}} title={fmtFull(m.created_at)}>
                <span>{fmtTime(m.created_at)}</span>{m.edited_at&&!m.deleted?<span>edited</span>:null}{mine&&!m.deleted?<Ticks seen={seen}/>:null}
                {!editing && !m.deleted && <span className="cg-msg-actions" style={{display:'flex',gap:10}}>
                  <span onClick={()=>setPickerFor(pickerFor===m.id?null:m.id)} style={actLink}>React</span>
                  <span onClick={()=>setReplyTo(m)} style={actLink}>Reply</span>
                  {mine && <span onClick={()=>startEdit(m)} style={actLink}>Edit</span>}
                  {mine && <span onClick={()=>del(m)} style={actLink}>Delete</span>}
                </span>}
              </div>
              {pickerFor===m.id && <div style={{position:'absolute',top:'100%',[mine?'right':'left']:0,zIndex:20,marginTop:2}}><ReactPicker onPick={(e)=>toggleReaction(m,e)}/></div>}
            </div>
          </React.Fragment>; })}
        {otherTyping && <div style={{alignSelf:'flex-start',fontSize:'.78rem',color:'var(--ink-faint)',display:'flex',alignItems:'center',gap:6,padding:'2px 4px'}}>coach typing<TypingDots/></div>}
      </div>
      {err && <div style={{padding:'4px 20px',color:'var(--red)',fontSize:'.78rem',fontFamily:'var(--font-mono)'}}>{err}</div>}
      {replyTo && <div style={{padding:'8px 20px',display:'flex',alignItems:'center',gap:10,borderTop:'1px solid var(--border)',background:'var(--surface)'}}>
        <div style={{flex:1,minWidth:0,fontSize:'.8rem',color:'var(--ink-dim)',borderLeft:'2px solid var(--border-gold)',paddingLeft:8,whiteSpace:'nowrap',overflow:'hidden',textOverflow:'ellipsis'}}>Replying to <strong>{replyTo.sender_name}</strong>: {(replyTo.body||'').slice(0,60)}</div>
        <span onClick={()=>setReplyTo(null)} style={{cursor:'pointer',color:'var(--ink-faint)',fontSize:'1rem',padding:'0 6px'}}>×</span>
      </div>}
      <div style={{padding:'12px 16px',borderTop:'1px solid var(--border)',display:'flex',gap:10}}>
        <textarea value={body} onChange={e=>{setBody(e.target.value); pingTyping();}} onKeyDown={e=>{ if(e.key==='Enter'&&!e.shiftKey){ e.preventDefault(); send(); } }} placeholder="Write a message…  (Enter to send)" rows={1} style={{flex:1,resize:'none',padding:'13px 14px',borderRadius:12,background:'var(--navy-950)',border:'1px solid var(--border)',color:'var(--ink)',fontFamily:'var(--font-body)',fontSize:'.92rem',maxHeight:120,minHeight:44}}/>
        <button className="btn btn-primary" style={{width:'auto',minHeight:44}} disabled={!body.trim()||sending} onClick={send}>Send</button>
      </div>
    </div>}
  </div>;
}
const actLink={cursor:'pointer',color:'var(--ink-faint)',textDecoration:'underline',padding:'4px 2px'};
function Lotus(){
  return <svg viewBox="0 0 48 44" width="26" height="24" aria-hidden="true">
    <defs><linearGradient id="cgLotus" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stopColor="#fbe6b0"/><stop offset="100%" stopColor="var(--gold-2)"/></linearGradient></defs>
    <g fill="url(#cgLotus)" stroke="rgba(10,17,36,.35)" strokeWidth=".6">
      <path d="M24 6c3 5 3 13 0 20-3-7-3-15 0-20z"/>
      <path d="M24 26C18 22 15 15 15 8c6 1 10 7 10 18z"/>
      <path d="M24 26C30 22 33 15 33 8c-6 1-10 7-10 18z"/>
      <path d="M24 27C16 27 8 24 3 18c8-3 17 0 21 9z"/>
      <path d="M24 27C32 27 40 24 45 18c-8-3-17 0-21 9z"/>
    </g>
    <path d="M9 30c4 5 9 7 15 7s11-2 15-7c-4 4-9 6-15 6s-11-2-15-6z" fill="rgba(245,217,122,.55)"/>
  </svg>;
}
window.StudentChat = StudentChat;
})();
