/* ============================================================
   PRIVATE GM CHANNEL — a two-way text thread between ONE player
   and the moderator. Renders ONLY on that player's device + the
   host inbox (same on-device privacy rule as secret roles).
   • GMMessagePlayer — floating "Message the GM" button + thread
   • GMInbox          — moderator inbox: one thread per player
   ============================================================ */
const { useState: useS_gm, useRef: useR_gm, useEffect: useE_gm } = React;

function gmFmtTime(t){ return new Date(t).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); }

/* ---------- thread bubble list (shared) ---------- */
function GMThread({ msgs, emptyHint }){
  const endRef = useR_gm(null);
  useE_gm(()=>{ if(endRef.current) endRef.current.scrollTop = endRef.current.scrollHeight; }, [msgs.length]);
  return (
    <div className="gm-thread no-scrollbar" ref={endRef}>
      {msgs.length===0 && <div className="gm-thread-empty">{emptyHint}</div>}
      {msgs.map(m=>(
        <div key={m.id} className={`gm-msg ${m.from}`}>
          <span className="gm-msg-text">{m.text}</span>
          <span className="gm-msg-time">{gmFmtTime(m.t)}</span>
        </div>
      ))}
    </div>
  );
}

/* ---------- PLAYER — floating button + private thread ---------- */
function GMMessagePlayer({ player, variant }){
  const game = useGame();
  const [open, setOpen] = useS_gm(false);
  const [draft, setDraft] = useS_gm('');
  const [pulse, setPulse] = useS_gm(false);
  const thread = (game.gm.threads[player.id] || []);
  const unread = thread.filter(m=>m.from==='gm' && !m.read).length;

  useGameEvents((ev)=>{
    if(ev.type==='gm-reply' && ev.playerId===player.id){ haptic(HAPTIC.intel); setPulse(true); setTimeout(()=>setPulse(false), 2200); }
  });
  useE_gm(()=>{ if(open) Game.markRead(player.id); }, [open, thread.length]);

  const send = ()=>{ const t=draft.trim(); if(!t) return; Game.sendPrivateMessage(player.id, t); setDraft(''); haptic([8]); };

  return (
    <>
      {variant==='dock'
        ? <button className={`dock-railbtn gm ${unread>0?'has-unread':''} ${pulse?'pulse':''}`} onClick={()=>setOpen(true)}
                  title="Message the Game Master">
            <Icon name="book" size={18}/>
            {unread>0 && <span className="gm-badge">{unread}</span>}
          </button>
        : <button className={`gm-fab ${unread>0?'has-unread':''} ${pulse?'pulse':''}`} onClick={()=>setOpen(true)}
                  title="Send a private message to the Game Master">
            <Icon name="book" size={16}/>
            <span className="gm-fab-label">Message the GM</span>
            {unread>0 && <span className="gm-badge">{unread}</span>}
          </button>}

      {open && (
        <div className="gm-modal" onClick={()=>setOpen(false)}>
          <div className="gm-panel liquid-glass" onClick={e=>e.stopPropagation()}>
            <div className="gm-panel-head">
              <div className="gm-panel-id">
                <span className="gm-panel-eyebrow">Private · only you &amp; the GM</span>
                <span className="gm-panel-title display">Game Master</span>
              </div>
              <button className="gm-x" onClick={()=>setOpen(false)}>✕</button>
            </div>
            <GMThread msgs={thread} emptyHint="Send a quiet word to the Game Master — a secret plan, a question, a request. Only they will see it."/>
            {window.PrivateWagerPlayerCard && <window.PrivateWagerPlayerCard player={player}/>}
            <div className="gm-compose">
              <textarea className="gm-input" rows="1" placeholder="Message the GM privately…" value={draft}
                onChange={e=>setDraft(e.target.value)}
                onKeyDown={e=>{ if(e.key==='Enter' && !e.shiftKey){ e.preventDefault(); send(); } }}/>
              <button className="gm-send glass-btn" disabled={!draft.trim()} onClick={send}>Send</button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
window.GMMessagePlayer = GMMessagePlayer;

/* ---------- MODERATOR — private inbox, one thread per player ---------- */
function GMInbox({ game }){
  const [openFor, setOpenFor] = useS_gm('');
  const [draft, setDraft] = useS_gm('');
  const threads = game.gm.threads || {};
  const players = game.players;

  const unreadFor = (pid)=> (threads[pid]||[]).filter(m=>m.from==='player' && !m.read).length;
  const lastOf = (pid)=>{ const th=threads[pid]||[]; return th.length? th[th.length-1] : null; };
  const totalUnread = players.reduce((n,p)=> n+unreadFor(p.id), 0);

  const openThread = (pid)=>{ setOpenFor(pid); setDraft(''); Game.markReadGM(pid); };
  const reply = ()=>{ const t=draft.trim(); if(!t||!openFor) return; Game.modReply(openFor, t); setDraft(''); };

  const active = openFor ? players.find(p=>p.id===openFor) : null;

  return (
    <div className="host-card liquid-glass">
      <h2 className="section-label"><Icon name="book" size={16}/> Private Inbox
        {totalUnread>0 && <span className="lbl-badge">{totalUnread}</span>}
      </h2>
      <p className="muted" style={{fontSize:'.74rem', textTransform:'none', letterSpacing:'.01em', margin:'0 0 .7rem'}}>
        Two-way private threads. Messages show only on that player's device and here — never on the Main screen or other phones.
      </p>

      {!active ? (
        <div className="gm-inbox-list">
          {players.length===0 && <div className="muted" style={{fontSize:'.78rem'}}>No heroes have joined yet.</div>}
          {players.map(p=>{
            const u = unreadFor(p.id); const last = lastOf(p.id);
            return (
              <button key={p.id} className={`gm-inbox-row ${u>0?'unread':''}`} onClick={()=>openThread(p.id)}>
                <span className="gm-inbox-name">{p.name.split(' ')[0]}</span>
                <span className="gm-inbox-preview">{last ? (last.from==='gm'?'You: ':'')+last.text : 'Start a private thread…'}</span>
                <span className="gm-inbox-meta">
                  {last && <span className="gm-inbox-time">{gmFmtTime(last.t)}</span>}
                  {u>0 && <span className="gm-badge">{u}</span>}
                </span>
              </button>
            );
          })}
        </div>
      ) : (
        <div className="gm-inbox-open">
          <div className="gm-inbox-bar">
            <button className="tiny-btn" onClick={()=>setOpenFor('')}>← Inbox</button>
            <span className="gm-inbox-with">Thread with <strong>{active.name.split(' ')[0]}</strong></span>
          </div>
          <GMThread msgs={threads[openFor]||[]} emptyHint={`No messages yet. Open a private line to ${active.name.split(' ')[0]}.`}/>
          {window.GMInboxActions && <window.GMInboxActions game={game} playerId={openFor}/>}
          <div className="gm-compose">
            <textarea className="gm-input" rows="1" placeholder={`Reply privately to ${active.name.split(' ')[0]}…`} value={draft}
              onChange={e=>setDraft(e.target.value)}
              onKeyDown={e=>{ if(e.key==='Enter' && !e.shiftKey){ e.preventDefault(); reply(); } }}/>
            <button className="gm-send glass-btn" disabled={!draft.trim()} onClick={reply}>Reply</button>
          </div>
        </div>
      )}
    </div>
  );
}
window.GMInbox = GMInbox;

/* ---------- PLAYER — private wager card (pinned in the GM panel) ---------- */
function PrivateWagerPlayerCard({ player }){
  const game = useGame();
  const pw = game.privateWagers[player.id];
  const [chosen, setChosen] = useS_gm('');
  const [stake, setStake] = useS_gm(1);
  useGameEvents((ev)=>{ if(ev.type==='pwager-resolve' && ev.playerId===player.id){ haptic(ev.won?HAPTIC.premium:HAPTIC.damage); } });
  if(!pw) return null;
  const max = player.coins||0;
  const clamp = (n)=>Math.max(0, Math.min(max, n));

  if(pw.status==='offered'){
    return (
      <div className="pw-card offered">
        <div className="pw-eyebrow">🎲 Private wager · only you &amp; the GM</div>
        <div className="pw-terms">{pw.terms}</div>
        <div className="pw-options">
          {pw.outcomes.map(o=>(
            <button key={o.id} className={`pw-opt ${chosen===o.id?'sel':''}`} onClick={()=>{ setChosen(o.id); haptic([6]); }}>{o.label}</button>
          ))}
        </div>
        <div className="pw-stake-row">
          <span className="pw-stake-lbl">Stake</span>
          <div className="pw-stepper">
            <button className="pw-step" onClick={()=>setStake(s=>clamp(s-1))}>−</button>
            <span className="pw-stake-amt">{stake}</span>
            <button className="pw-step" onClick={()=>setStake(s=>clamp(s+1))}>+</button>
            <button className="pw-step max" onClick={()=>setStake(max)} disabled={max<=0}>max</button>
          </div>
          <span className="pw-purse">{max}c purse</span>
        </div>
        <button className="pw-place glass-btn" disabled={!chosen || stake<=0 || stake>max}
          onClick={()=>{ Game.placePrivateWager(player.id, chosen, stake); haptic([10]); }}>
          Place bet · {stake}c
        </button>
      </div>
    );
  }
  if(pw.status==='placed'){
    const ch = pw.outcomes.find(o=>o.id===pw.chosen)||{};
    return (
      <div className="pw-card placed">
        <div className="pw-eyebrow">🎲 Wager pending</div>
        <div className="pw-pending">You bet <strong>{pw.stake}c</strong> on “<strong>{ch.label}</strong>”. Hidden until the GM calls it.</div>
      </div>
    );
  }
  // resolved
  return (
    <div className={`pw-card resolved ${pw.won?'win':'lose'}`}>
      <div className="pw-eyebrow">{pw.won?'🎉 You won':'🎲 Wager lost'}</div>
      <div className="pw-pending">{pw.won
        ? <>Your reward arrived privately — check your purse, inventory, or secrets.</>
        : <>Your {pw.stake}c stake is gone.</>}</div>
    </div>
  );
}
window.PrivateWagerPlayerCard = PrivateWagerPlayerCard;

/* ---------- MODERATOR — wager actions inside a player's thread ---------- */
function GMInboxActions({ game, playerId }){
  const pw = game.privateWagers[playerId];
  const [open, setOpen] = useS_gm(false);
  const [terms, setTerms] = useS_gm('');
  const [oa, setOa] = useS_gm('');
  const [ob, setOb] = useS_gm('');
  const [rType, setRType] = useS_gm('coins');
  const [rAmt, setRAmt] = useS_gm(15);
  const [rItem, setRItem] = useS_gm('');
  const [rRole, setRRole] = useS_gm('');
  const player = game.players.find(p=>p.id===playerId);

  if(pw){
    if(pw.status==='offered'){
      return <div className="pw-mod waiting">
        <span>Wager offered — waiting for {player?player.name.split(' ')[0]:'them'} to place…</span>
        <button className="tiny-btn danger-outline" onClick={()=>Game.cancelPrivateWager(playerId)}>Cancel</button>
      </div>;
    }
    if(pw.status==='placed'){
      const ch = pw.outcomes.find(o=>o.id===pw.chosen)||{};
      return <div className="pw-mod resolve">
        <div className="pw-mod-line">Bet: <strong>{pw.stake}c</strong> on “{ch.label}” · reward: {window.rewardLabel?window.rewardLabel(pw.reward):''}</div>
        <div className="pw-mod-btns">
          <button className="chip-btn on" onClick={()=>Game.resolvePrivateWager(playerId, true)}>✓ Won</button>
          <button className="chip-btn" onClick={()=>Game.resolvePrivateWager(playerId, false)}>✗ Lost</button>
          <button className="tiny-btn danger-outline" onClick={()=>Game.cancelPrivateWager(playerId)}>Cancel</button>
        </div>
      </div>;
    }
    // resolved
    return <div className="pw-mod done">
      <span>Wager resolved — {pw.won?'won':'lost'}.</span>
      <button className="tiny-btn" onClick={()=>Game.cancelPrivateWager(playerId)}>Clear</button>
    </div>;
  }

  if(!open){
    return <button className="pw-offer-btn" onClick={()=>setOpen(true)}><Icon name="buy" size={13}/> Offer a private wager</button>;
  }
  const send = ()=>{
    const reward = rType==='coins' ? { type:'coins', amount:Number(rAmt)||0 }
      : rType==='item' ? { type:'item', item:rItem||'A mysterious gift' }
      : { type:'boon', role:rRole||'Hidden Boon', item:rItem||'A secret advantage only you know.' };
    Game.openPrivateWager(playerId, terms, [oa, ob], reward);
    setOpen(false); setTerms(''); setOa(''); setOb(''); setRItem(''); setRRole('');
  };
  return (
    <div className="pw-form">
      <div className="pw-form-title">Offer a private wager</div>
      <input className="tinput" placeholder="Terms — e.g. We clear this boss in 3 rounds" value={terms} onChange={e=>setTerms(e.target.value)}/>
      <div className="pw-form-row">
        <input className="tinput" placeholder="Outcome A" value={oa} onChange={e=>setOa(e.target.value)}/>
        <input className="tinput" placeholder="Outcome B" value={ob} onChange={e=>setOb(e.target.value)}/>
      </div>
      <div className="section-sub">Reward if they win</div>
      <div className="radio-row">
        {['coins','item','boon'].map(t=>(<button key={t} className={`chip-btn ${rType===t?'on':''}`} onClick={()=>setRType(t)}>{t}</button>))}
      </div>
      {rType==='coins' && <input className="tinput" type="number" min="0" placeholder="Coin amount" value={rAmt} onChange={e=>setRAmt(e.target.value)}/>}
      {rType==='item' && <input className="tinput" placeholder="Item name" value={rItem} onChange={e=>setRItem(e.target.value)}/>}
      {rType==='boon' && <div className="pw-form-row">
        <input className="tinput" placeholder="Boon title" value={rRole} onChange={e=>setRRole(e.target.value)}/>
        <input className="tinput" placeholder="Boon effect (secret)" value={rItem} onChange={e=>setRItem(e.target.value)}/>
      </div>}
      <div className="pw-form-btns">
        <button className="tiny-btn" onClick={()=>setOpen(false)}>Cancel</button>
        <button className="chip-btn on" disabled={!oa.trim()||!ob.trim()} onClick={send}>Send offer →</button>
      </div>
    </div>
  );
}
window.GMInboxActions = GMInboxActions;
