// cal-ui.jsx — calendar helpers + sync/zoom modals + event editor/popover.
const { useState: cuState, useEffect: cuEffect, useRef: cuRef } = React;
const CR = window.RAISE;
const { PersonChip, PersonCombo, toast: cuToast } = window.RaiseShell;
const Store_ = window.RaiseStore;

// ── date helpers ────────────────────────────────────────────────────
const DAYNAMES = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December'];
function mondayOf(d){ const m=new Date(d); m.setHours(0,0,0,0); m.setDate(d.getDate()-((d.getDay()+6)%7)); return m; }
function addDays(d,n){ const x=new Date(d); x.setDate(d.getDate()+n); return x; }
function sameDay(a,b){ return a.getFullYear()===b.getFullYear()&&a.getMonth()===b.getMonth()&&a.getDate()===b.getDate(); }
function fmtTime(d){ let h=d.getHours(), m=d.getMinutes(); const ap=h>=12?'PM':'AM'; h=h%12; if(h===0)h=12; return m? `${h}:${String(m).padStart(2,'0')} ${ap}` : `${h} ${ap}`; }
function fmtRange(s,e){ const a=fmtTime(s), b=fmtTime(e); return a+' – '+b; }
function durMin(s,e){ return Math.round((e-s)/60000); }
function fmtDur(min){ if(min<60) return min+' min'; const h=min/60; return (h%1===0?h:h.toFixed(1))+' hr'; }
function isoAt(date,h,m){ const d=new Date(date); d.setHours(h,m||0,0,0); return d.toISOString(); }
function roundToHalf(d){ const x=new Date(d); x.setMinutes(x.getMinutes()<30?0:30,0,0); return x; }

// resolve a fuzzy todo reminder ("Today 1:30 PM", "Fri", "Mon 4:00 PM") to a Date
function reminderDate(str){
  if(!str) return null; const now=new Date(); const s=str.toLowerCase();
  let base=null; const names={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6};
  if(s.includes('today')) base=new Date(now);
  else if(s.includes('tomorrow')) base=addDays(now,1);
  else { for(const k in names){ if(s.includes(k)){ const mon=mondayOf(now); base=addDays(mon,(names[k]+6)%7); break; } } }
  if(!base) return null;
  const tm=/(\d{1,2})(?::(\d{2}))?\s*(am|pm)/.exec(s);
  if(tm){ let h=+tm[1]%12; if(tm[3]==='pm') h+=12; base.setHours(h,tm[2]?+tm[2]:0,0,0); return {date:base,timed:true}; }
  base.setHours(0,0,0,0); return {date:base,timed:false};
}

// overlap lanes: assign each event a column among mutually-overlapping events
function layoutDay(items){ // items:[{start:Date,end:Date,...}]
  const sorted=[...items].sort((a,b)=>a.start-b.start||b.end-a.end);
  const out=[]; let cluster=[]; let clusterEnd=null;
  const flush=()=>{ const lanes=[]; cluster.forEach(it=>{ let li=lanes.findIndex(l=>l<=it.start); if(li<0){li=lanes.length; lanes.push(it.end);} else lanes[li]=it.end; it._lane=li; }); cluster.forEach(it=>{ it._lanes=lanes.length; out.push(it); }); cluster=[]; clusterEnd=null; };
  sorted.forEach(it=>{ if(cluster.length && it.start>=clusterEnd){ flush(); } cluster.push(it); clusterEnd=clusterEnd?new Date(Math.max(clusterEnd,it.end)):it.end; });
  flush(); return out;
}

const SYNC = {
  synced:    { label:'Synced',     cls:'ok',   dot:'#3f9560' },
  syncing:   { label:'Syncing…',   cls:'busy', dot:'#c08a2a' },
  'local-only':{ label:'Not synced', cls:'idle', dot:'#a89e8e' },
  conflict:  { label:'Conflict',   cls:'warn', dot:'#c96442' },
};
function SyncDot({ state }){ const m=SYNC[state]||SYNC['local-only']; return <span className={'syncpill '+m.cls} title={m.label}><span className="sd" style={{background:m.dot}}/>{m.label}</span>; }

// ── Google connect / account-picker modal ──────────────────────────
function GoogleConnectModal({ cal, onClose }){
  const [picked,setPicked]=cuState(cal.google.accounts[0]);
  const [phase,setPhase]=cuState('pick'); // pick → granting
  const go=()=>{ setPhase('granting'); setTimeout(()=>{ Store_.connectGoogle(picked); cuToast('Google Calendar connected'); onClose(); }, 900); };
  return (
    <div className="modal-back" onClick={onClose}>
      <div className="gmodal" onClick={e=>e.stopPropagation()}>
        <div className="gmodal-head">
          <div className="gmark"><svg viewBox="0 0 24 24" width="20" height="20"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.76h3.56c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.56-2.76c-.98.66-2.23 1.06-3.72 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84A11 11 0 0 0 12 23z"/><path fill="#FBBC05" d="M5.84 14.11a6.6 6.6 0 0 1 0-4.22V7.05H2.18a11 11 0 0 0 0 9.9z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.05l3.66 2.84C6.71 7.31 9.14 5.38 12 5.38z"/></svg></div>
          <div><b>Connect Google Calendar</b><span>Two-way sync · events flow both directions</span></div>
        </div>
        {phase==='pick' ? (
          <>
            <div className="gacct-label">Choose an account</div>
            <div className="gacct-list">
              {cal.google.accounts.map(a=>(
                <button key={a} className={'gacct'+(picked===a?' on':'')} onClick={()=>setPicked(a)}>
                  <span className="gacct-av" style={{background: picked===a?'#c96442':'#b7ad9c'}}>{a[0].toUpperCase()}</span>
                  <span className="gacct-nm">{a}<small>Google account</small></span>
                  <span className={'gradio'+(picked===a?' on':'')}/>
                </button>
              ))}
            </div>
            <div className="gscope">Raise OS will be able to <b>see, edit and create</b> events on calendars you map.</div>
            <div className="gbtns">
              <button className="gbtn ghost" onClick={onClose}>Cancel</button>
              <button className="gbtn primary" onClick={go}>Allow access</button>
            </div>
          </>
        ) : (
          <div className="ggrant"><span className="gspin"/><b>Connecting to Google…</b><span>Authorizing {picked}</span></div>
        )}
      </div>
    </div>
  );
}

// ── per-calendar mapping settings ───────────────────────────────────
function SyncSettings({ cal, onClose }){
  const g=cal.google;
  // Reflect the REAL Google connection (from RaiseLive), not mock seed state.
  const RL = window.RaiseLive;
  const [conns] = RL ? RL.useConnections() : [{}];
  const gc = (conns && conns.google_calendar) || { status:'disconnected' };
  const connected = gc.status==='connected';
  const account = gc.account_email || g.account;
  const lastSync = gc.last_sync;
  const fmt = (t)=> t ? new Date(t).toLocaleString('en-US',{month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}) : null;
  const connect = ()=>{ if(window.RaiseGoogle) window.RaiseGoogle.connect(); else { onClose(); window.dispatchEvent(new CustomEvent('cal:connect')); } };
  const disconnect = async ()=>{ if(RL && RL.setConnStatus){ await RL.setConnStatus('gmail',{status:'disconnected',account_email:null,last_sync:null}); await RL.setConnStatus('google_calendar',{status:'disconnected',account_email:null,last_sync:null}); } };
  return (
    <div className="modal-back" onClick={onClose}>
      <div className="setmodal" onClick={e=>e.stopPropagation()}>
        <div className="setmodal-head"><b>Calendar sync settings</b><button className="xbtn" onClick={onClose}>✕</button></div>
        <div className="setrow-top">
          <div className="setacct">
            <span className="syncbig" style={{background:connected?'#eaf3ee':'#f0ece2'}}/>
            <div><b>{connected?account:'Not connected'}</b><span>{connected? (fmt(lastSync)?'Last synced '+fmt(lastSync):'Connected'):'Connect to enable live sync'}</span></div>
          </div>
          {connected
            ? <button className="gbtn ghost danger" onClick={disconnect}>Disconnect</button>
            : <button className="gbtn primary" onClick={connect}>Connect</button>}
        </div>
        <div className="setmap-h">Calendar mapping</div>
        {connected ? <>
        <div className="setmap-sub">Your Google primary calendar syncs to a Raise OS calendar. Two-way means edits sync in both directions.</div>
        <div className="setmap-list">
          {g.remotes.map(r=>(
            <div className="maprow" key={r.gid}>
              <span className="mapdot" style={{background:r.color}}/>
              <span className="mapname">{r.gid==='g-primary' && account ? account : r.name}</span>
              <svg className="maparrow" viewBox="0 0 24 12" width="22"><path d="M2 6h18M16 2l4 4-4 4" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>
              <select className="mapsel" value={r.mapTo||''} onChange={e=>Store_.setMapping(r.gid,e.target.value||null)}>
                <option value="">— Don’t sync —</option>
                {cal.calendars.map(c=><option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
              <button className={'twbtn'+(r.twoWay?' on':'')} disabled={!r.mapTo} onClick={()=>Store_.toggleTwoWay(r.gid)} title="Two-way sync">
                <svg viewBox="0 0 16 12" width="16"><path d="M4 2L1 5l3 3M1 5h11M12 10l3-3-3-3M15 7H4" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/></svg>
                {r.twoWay?'Two-way':'One-way'}
              </button>
            </div>
          ))}
        </div></>
        : <div className="setmap-sub">Connect your Google account to map and sync your real calendars.</div>}
      </div>
    </div>
  );
}

// ── conflict resolution modal ───────────────────────────────────────
function ConflictModal({ ev, onClose }){
  const c=ev.conflict; const ms=new Date(ev.start), me=new Date(ev.end);
  const ts=new Date(c.remote.start), te=new Date(c.remote.end);
  const resolve=(choice)=>{ Store_.resolveConflict(ev.id,choice); cuToast(choice==='both'?'Kept both versions':'Conflict resolved'); onClose(); };
  return (
    <div className="modal-back" onClick={onClose}>
      <div className="cfmodal" onClick={e=>e.stopPropagation()}>
        <div className="cfhead"><span className="cfbadge">SYNC CONFLICT</span><b>{ev.title}</b><span>This event changed in both places since the last sync.</span></div>
        <div className="cfcols">
          <div className="cfcard mine">
            <div className="cfk">Raise OS</div>
            <div className="cftime">{DAYNAMES[(ms.getDay()+6)%7]} · {fmtRange(ms,me)}</div>
            <div className="cfnote">Your local version.</div>
            <button className="gbtn ghost" onClick={()=>resolve('mine')}>Keep mine</button>
          </div>
          <div className="cfvs">vs</div>
          <div className="cfcard theirs">
            <div className="cfk">Google</div>
            <div className="cftime">{DAYNAMES[(ts.getDay()+6)%7]} · {fmtRange(ts,te)}</div>
            <div className="cfnote">{c.remote.note}</div>
            <button className="gbtn ghost" onClick={()=>resolve('theirs')}>Keep Google</button>
          </div>
        </div>
        <div className="cffoot">
          <button className="gbtn primary wide" onClick={()=>resolve('both')}>Keep both as separate events</button>
        </div>
      </div>
    </div>
  );
}

// ── event detail / editor popover ───────────────────────────────────
function EventPopover({ ev, anchorRect, onClose, onConflict, isNew }){
  const cal=window.RaiseStore.getCal();
  const [edit,setEdit]=cuState(!!isNew);
  const [draft,setDraft]=cuState(()=>({ ...ev }));
  const calObj=cal.calendars.find(c=>c.id===(edit?draft.calId:ev.calId))||cal.calendars[0];
  const s=new Date(edit?draft.start:ev.start), e=new Date(edit?draft.end:ev.end);

  // position: to the right of the anchor, clamped to viewport
  const W=320; let left=anchorRect.right+10, top=anchorRect.top;
  if(left+W>window.innerWidth-12) left=Math.max(12, anchorRect.left-W-10);
  top=Math.min(top, window.innerHeight-360); top=Math.max(12,top);

  const save=()=>{ if(isNew){ Store_.addEvent(draft); cuToast('Event created'); } else { Store_.patchEvent(ev.id,draft); cuToast('Event updated'); } onClose(); };
  const del=()=>{ Store_.removeEvent(ev.id); cuToast('Event deleted'); onClose(); };
  const setTime=(which,val)=>{ const [h,m]=val.split(':').map(Number); const base=new Date(which==='start'?draft.start:draft.end); base.setHours(h,m,0,0);
    if(which==='start'){ const oldDur=durMin(new Date(draft.start),new Date(draft.end)); const ne=new Date(base.getTime()+oldDur*60000); setDraft(d=>({...d,start:base.toISOString(),end:ne.toISOString()})); }
    else setDraft(d=>({...d,end:base.toISOString()})); };
  const tval=(d)=>`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;

  return (
    <>
      <div className="pop-back" onClick={onClose}/>
      <div className="evpop" style={{left,top}} onClick={e=>e.stopPropagation()}>
        <span className="evpop-bar" style={{background:calObj.color}}/>
        <button className="evpop-x" onClick={onClose}>✕</button>
        {edit ? (
          <div className="evform">
            <input className="evtitle-in" autoFocus placeholder="Add title" value={draft.title} onChange={ev2=>setDraft(d=>({...d,title:ev2.target.value}))}/>
            <div className="evf-row">
              <span className="evf-ic">🕑</span>
              <span className="evf-day">{DAYNAMES[(s.getDay()+6)%7]} {MONTHS[s.getMonth()].slice(0,3)} {s.getDate()}</span>
              <input type="time" className="evtime-in" value={tval(s)} onChange={e2=>setTime('start',e2.target.value)}/>
              <span className="evf-dash">–</span>
              <input type="time" className="evtime-in" value={tval(e)} onChange={e2=>setTime('end',e2.target.value)}/>
            </div>
            <div className="evf-row">
              <span className="evf-ic">📅</span>
              <select className="evf-sel" value={draft.calId} onChange={e2=>setDraft(d=>({...d,calId:e2.target.value}))}>
                {cal.calendars.map(c=><option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </div>
            <div className="evf-row"><span className="evf-ic">👤</span><div className="evf-grow"><PersonCombo value={draft.personId||'self'} onChange={id=>setDraft(d=>({...d,personId:id==='self'?null:id}))}/></div></div>
            <div className={'zoomtoggle'+(draft.zoom?' on':'')}>
              <span className="zt-ic"><svg viewBox="0 0 28 28" width="17" height="17"><rect width="28" height="28" rx="7" fill="#2D8CFF"/><path d="M6 10.5c0-.83.67-1.5 1.5-1.5h7c.83 0 1.5.67 1.5 1.5v7c0 .83-.67 1.5-1.5 1.5h-7A1.5 1.5 0 0 1 6 17.5zM17 12l4-2.3c.4-.23.9.06.9.52v7.56c0 .46-.5.75-.9.52L17 16z" fill="#fff"/></svg></span>
              <div className="zt-txt"><b>Zoom meeting</b><span>{cal.zoom.connected? (draft.zoom?'Link generated':'Add a join link'):'Connect Zoom in settings'}</span></div>
              <button className={'switch'+(draft.zoom?' on':'')} disabled={!cal.zoom.connected}
                onClick={()=>setDraft(d=>({...d, zoom:d.zoom?null:window.RaiseStore.getCal()&&makeZoomLocal()}))}><i/></button>
            </div>
            {draft.zoom && <div className="zoomdetail mono">{draft.zoom.url}<br/>ID {draft.zoom.meetingId} · Passcode {draft.zoom.passcode}</div>}
            <textarea className="evnote-in" placeholder="Notes" value={draft.notes||''} onChange={e2=>setDraft(d=>({...d,notes:e2.target.value}))}/>
            <div className="evform-btns">
              {!isNew && <button className="gbtn ghost danger" onClick={del}>Delete</button>}
              <div className="evform-spacer"/>
              <button className="gbtn ghost" onClick={onClose}>Cancel</button>
              <button className="gbtn primary" onClick={save} disabled={!draft.title.trim()}>{isNew?'Create':'Save'}</button>
            </div>
          </div>
        ) : (
          <div className="evview">
            <h4>{ev.title}</h4>
            <div className="evv-time">{DAYNAMES[(s.getDay()+6)%7]}, {MONTHS[s.getMonth()]} {s.getDate()} · {fmtRange(s,e)} <span className="evv-dur">({fmtDur(durMin(s,e))})</span></div>
            <div className="evv-cal"><span className="evv-dot" style={{background:calObj.color}}/>{calObj.name}<SyncDot state={ev.syncState}/></div>
            {ev.syncState==='conflict' && <button className="cfbtn" onClick={()=>onConflict(ev)}>⚠ Resolve sync conflict</button>}
            {ev.personId && <div className="evv-person"><PersonChip id={ev.personId} sub/></div>}
            {ev.location && <div className="evv-loc">📍 {ev.location}</div>}
            {ev.zoom && (
              <a className="evv-zoom" href={ev.zoom.url} target="_blank" rel="noreferrer">
                <span className="zt-ic"><svg viewBox="0 0 28 28" width="18" height="18"><rect width="28" height="28" rx="7" fill="#2D8CFF"/><path d="M6 10.5c0-.83.67-1.5 1.5-1.5h7c.83 0 1.5.67 1.5 1.5v7c0 .83-.67 1.5-1.5 1.5h-7A1.5 1.5 0 0 1 6 17.5zM17 12l4-2.3c.4-.23.9.06.9.52v7.56c0 .46-.5.75-.9.52L17 16z" fill="#fff"/></svg></span>
                <span className="evv-zoom-t"><b>Join Zoom Meeting</b><small className="mono">ID {ev.zoom.meetingId} · {ev.zoom.passcode}</small></span>
              </a>
            )}
            {ev.notes && <div className="evv-notes">{ev.notes}</div>}
            <div className="evview-btns">
              <button className="gbtn primary" onClick={()=>{ setDraft({...ev}); setEdit(true); }}>Edit</button>
              <button className="gbtn ghost danger" onClick={del}>Delete</button>
            </div>
          </div>
        )}
      </div>
    </>
  );
}
// local zoom maker (mirror of shell's makeZoom)
function makeZoomLocal(){ const a=Math.floor(100+Math.random()*900),b=Math.floor(1000+Math.random()*9000),c=Math.floor(1000+Math.random()*9000);
  return { url:'https://zoom.us/j/'+`${a}${b}${c}`, meetingId:`${a} ${b} ${c}`, passcode:Math.random().toString(36).slice(2,8), host:'AJ · Fund II' }; }

window.CalUI = { DAYNAMES, MONTHS, mondayOf, addDays, sameDay, fmtTime, fmtRange, durMin, fmtDur, isoAt, roundToHalf,
  reminderDate, layoutDay, SyncDot, GoogleConnectModal, SyncSettings, ConflictModal, EventPopover, SYNC };
