// terminal-inbox.jsx — Council Proposals inbox screen.
// Polls /api/v1/proposals?status=pending; renders cards w/ APPROVE/DECLINE.
// Bearer pulled from sessionStorage (same shared slot as chat/backtest).
//
// This is THE competitor-wedge surface: agents propose, user approves
// with full context. Lives as a phone-frame screen routed at #inbox.

const INBOX_API = 'https://tradexchange.cc/api/v1/proposals';
const BEARER_KEY = 'tx-backtest-bearer';   // shared bearer slot

function getInboxBearer() {
  try { return sessionStorage.getItem(BEARER_KEY) || ''; } catch { return ''; }
}

async function fetchProposals(status) {
  const bearer = getInboxBearer();
  if (!bearer) return { error: 'no_bearer', proposals: [] };
  try {
    const r = await fetch(`${INBOX_API}?status=${encodeURIComponent(status)}&limit=50`, {
      headers: { 'authorization': 'Bearer ' + bearer },
    });
    if (!r.ok) {
      const text = await r.text();
      return { error: `${r.status}: ${text.slice(0, 200)}`, proposals: [] };
    }
    return await r.json();
  } catch (e) { return { error: e.message, proposals: [] }; }
}

async function actOnProposal(id, action) {
  const bearer = getInboxBearer();
  if (!bearer) return { ok: false, error: 'no_bearer' };
  try {
    const r = await fetch(`${INBOX_API}/${id}/${action}`, {
      method: 'GET',  // signed-URL endpoint accepts GET; bearer auth path also GET
      headers: { 'authorization': 'Bearer ' + bearer },
    });
    if (!r.ok) {
      let j; try { j = await r.json(); } catch { j = { error: r.statusText }; }
      return { ok: false, status: r.status, ...j };
    }
    const j = await r.json();
    return { ok: true, ...j };
  } catch (e) { return { ok: false, error: e.message }; }
}

const RULE_LABEL = {
  'profit-target': 'PROFIT TARGET HIT',
  'trailing-stop': 'TRAILING STOP',
  'eos-warning':   'END-OF-SESSION',
};

function ProposalCard({ p, onActed }) {
  const [busy, setBusy] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const act = async (action) => {
    setBusy(true);
    const res = await actOnProposal(p.id, action);
    setBusy(false);
    setResult(res);
    if (res.ok) {
      window.__txToast && window.__txToast(`✓ ${action === 'approve' ? 'Approved' : 'Declined'} ${p.symbol}`);
      setTimeout(onActed, 600);
    } else {
      window.__txToast && window.__txToast(`Failed: ${res.message || res.error || res.status}`, { error: true });
    }
  };
  const pnlGreen = (p.pnl_pct || 0) >= 0;
  const expiresIn = Math.max(0, Math.floor((new Date(p.expires_at).getTime() - Date.now()) / 1000 / 60));
  const created = new Date(p.created_at);
  const minsAgo = Math.floor((Date.now() - created.getTime()) / 1000 / 60);

  return (
    <div style={{
      margin: '0 16px 12px', padding: '14px 16px',
      background: TM.surfaceHi, border: `1px solid ${TM.cyan}44`, borderRadius: 12,
    }}>
      {/* Header */}
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8 }}>
        <div>
          <div style={{ fontFamily: GM, fontSize: 9.5, color: TM.cyan, letterSpacing: 1.2, fontWeight: 600 }}>
            {p.agent_id} · {RULE_LABEL[p.rule] || p.rule.toUpperCase()}
          </div>
          <div style={{ marginTop: 4, fontFamily: GM, fontSize: 16, fontWeight: 600, color: TM.text, letterSpacing: -0.2 }}>
            {p.side.toUpperCase()} {Number(p.qty_shares).toFixed(4)} {p.symbol}
          </div>
        </div>
        <span style={{ fontFamily: GM, fontSize: 9.5, color: TM.muted, letterSpacing: 0.6 }}>
          {minsAgo < 1 ? 'just now' : `${minsAgo}m ago`}
        </span>
      </div>

      {/* Council vote pill */}
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginBottom: 10,
        padding: '3px 8px', background: TM.cyanSoft, border: `1px solid ${TM.cyan}55`,
        borderRadius: 4, fontFamily: GM, fontSize: 10, color: TM.cyan, letterSpacing: 0.6, fontWeight: 600 }}>
        COUNCIL {p.council_yes}/25 APPROVE
      </div>

      {/* Rationale */}
      <p style={{ margin: '0 0 12px', fontFamily: GE, fontSize: 13, color: TM.textDim, lineHeight: 1.55, letterSpacing: -0.05 }}>
        {p.rationale}
      </p>

      {/* Context grid */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 12,
        padding: '10px 12px', background: 'rgba(244,244,240,0.03)', borderRadius: 6,
        fontFamily: GM, fontSize: 10.5, color: TM.muted, letterSpacing: 0.3 }}>
        <span>cost ${Number(p.avg_entry_price || 0).toFixed(2)}</span>
        <span style={{ textAlign: 'right', color: TM.text }}>now ${Number(p.current_price || 0).toFixed(2)}</span>
        <span>P&L</span>
        <span style={{ textAlign: 'right', color: pnlGreen ? TM.green : TM.red }}>
          {pnlGreen ? '+' : ''}${Number(p.unrealized_pnl_usd || 0).toFixed(2)} ({((p.pnl_pct || 0) * 100).toFixed(2)}%)
        </span>
        <span>expires</span>
        <span style={{ textAlign: 'right', color: expiresIn <= 3 ? TM.orange : TM.text }}>{expiresIn}m</span>
      </div>

      {/* Action buttons */}
      <div style={{ display: 'flex', gap: 8 }}>
        <button onClick={() => act('approve')} disabled={busy} style={{
          flex: 1, padding: '12px 14px', borderRadius: 8,
          background: TM.green, color: TM.ink,
          fontFamily: GE, fontSize: 14, fontWeight: 700, letterSpacing: -0.1,
          opacity: busy ? 0.5 : 1, cursor: busy ? 'wait' : 'pointer',
        }}>APPROVE</button>
        <button onClick={() => act('decline')} disabled={busy} style={{
          flex: 1, padding: '12px 14px', borderRadius: 8,
          background: TM.surfaceHi, color: TM.red,
          border: `1px solid ${TM.red}`,
          fontFamily: GE, fontSize: 14, fontWeight: 700, letterSpacing: -0.1,
          opacity: busy ? 0.5 : 1, cursor: busy ? 'wait' : 'pointer',
        }}>DECLINE</button>
      </div>
    </div>
  );
}

function InboxScreen() {
  const [statusTab, setStatusTab] = React.useState('pending');
  const [data, setData] = React.useState({ proposals: [], error: null, loading: true });

  const reload = React.useCallback(async () => {
    setData(d => ({ ...d, loading: true }));
    const r = await fetchProposals(statusTab);
    setData({ proposals: r.proposals || [], error: r.error || null, loading: false });
  }, [statusTab]);

  React.useEffect(() => {
    reload();
    // Poll every 30s to surface new proposals as cron fires
    const id = setInterval(reload, 30000);
    return () => clearInterval(id);
  }, [reload]);

  const bearer = getInboxBearer();

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflowY: 'auto' }} className="tx-scroll">
      <TopBar title="Inbox" subtitle={`Council proposals · ${data.proposals.length} ${statusTab}`}
        right={<button onClick={reload} style={{ width: 32, height: 32, borderRadius: 16, color: TM.muted }} title="Reload">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
            <path d="M21 12a9 9 0 11-3-6.7M21 3v6h-6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </button>}/>

      <div style={{ padding: '12px 16px 0' }}>
        <Segmented value={statusTab} onChange={setStatusTab} options={[
          { key: 'pending',  label: 'Pending' },
          { key: 'approved', label: 'Approved' },
          { key: 'declined', label: 'Declined' },
          { key: 'executed', label: 'Executed' },
        ]}/>
      </div>

      {!bearer && (
        <div style={{ margin: '14px 16px', padding: '14px 16px', background: TM.orangeSoft, border: `1px solid ${TM.orange}55`, borderRadius: 10 }}>
          <div style={{ fontFamily: GM, fontSize: 9.5, color: TM.orange, letterSpacing: 1.2, fontWeight: 600 }}>BEARER REQUIRED</div>
          <div style={{ marginTop: 6, fontFamily: GE, fontSize: 13, color: TM.text, lineHeight: 1.55 }}>
            Paste your EXECUTION_BEARER at <a href="backtest.html" style={{ color: TM.cyan }}>/backtest.html</a> once — it persists for this session and unlocks Inbox + Backtest + Chat.
          </div>
        </div>
      )}

      {data.error && (
        <div style={{ margin: '14px 16px', padding: '14px 16px', background: TM.redSoft, border: `1px solid ${TM.red}55`, borderRadius: 10 }}>
          <div style={{ fontFamily: GM, fontSize: 9.5, color: TM.red, letterSpacing: 1.2, fontWeight: 600 }}>ERROR</div>
          <div style={{ marginTop: 6, fontFamily: GM, fontSize: 12, color: TM.text, lineHeight: 1.5 }}>{data.error}</div>
        </div>
      )}

      {!data.loading && !data.error && data.proposals.length === 0 && (
        <div style={{ padding: '60px 32px', textAlign: 'center' }}>
          <div style={{ fontFamily: GE, fontSize: 36, marginBottom: 8 }}>✉</div>
          <div style={{ fontFamily: GE, fontSize: 14, fontWeight: 600, color: TM.text, marginBottom: 4 }}>
            No {statusTab} proposals
          </div>
          <div style={{ fontFamily: GE, fontSize: 12, color: TM.muted, lineHeight: 1.55, maxWidth: 320, margin: '0 auto' }}>
            Council cron checks every 5 min during market hours and emails you when a position hits a trigger (profit target +5%, trailing stop −3%, or 15 min before close).
          </div>
        </div>
      )}

      <div style={{ marginTop: 14 }}>
        {data.proposals.map(p => (
          <ProposalCard key={p.id} p={p} onActed={reload}/>
        ))}
      </div>

      <div style={{ height: 24 }}/>
    </div>
  );
}

Object.assign(window, { InboxScreen, ProposalCard });
