// P3 inbox smoke: Alice sends → Bob's inbox gets a NEEDS_REPLY item → Bob reads
// → item auto-resolves to DONE. Requires the service running (relay timer on),
// IIOS_DEV_TOKENS not needed (we sign locally). Run: node scripts/smoke-inbox.mjs
import 'dotenv/config';
import { io } from 'socket.io-client';
import jwt from 'jsonwebtoken';

const SERVICE = process.env.SMOKE_URL ?? 'http://localhost:3200';
const APP_ID = 'portal-demo';
const SECRET = JSON.parse(process.env.APP_SECRETS ?? '{"portal-demo":"dev-secret"}')[APP_ID];

const sign = (u) => jwt.sign({ sub: u, name: u, appId: APP_ID, orgId: `org_${APP_ID}` }, SECRET, { algorithm: 'HS256', expiresIn: '1h' });
const connect = (u) => io(`${SERVICE}/message`, { auth: { token: sign(u) }, transports: ['websocket'], forceNew: true });
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const assert = (c, m) => {
  if (!c) { console.error('✗', m); process.exit(1); }
  console.log('✓', m);
};

async function inbox(token, state) {
  const r = await fetch(`${SERVICE}/v1/inbox/items${state ? `?state=${state}` : ''}`, {
    headers: { authorization: `Bearer ${token}` },
  });
  if (!r.ok) throw new Error(`inbox ${r.status}`);
  return r.json();
}
async function pollUntil(fn, ms = 8000) {
  const end = Date.now() + ms;
  while (Date.now() < end) {
    const v = await fn();
    if (v) return v;
    await sleep(300);
  }
  return null;
}

const bobToken = sign('bob');
const alice = connect('alice');
const bob = connect('bob');

try {
  const { threadId } = await alice.emitWithAck('open_thread', {});
  await bob.emitWithAck('open_thread', { threadId }); // Bob joins → participant
  const sent = await alice.emitWithAck('send_message', { threadId, content: 'hi bob' });

  const open = await pollUntil(async () => {
    const items = await inbox(bobToken, 'OPEN');
    return items.find((i) => i.threadId === threadId && i.kind === 'NEEDS_REPLY') ?? null;
  });
  assert(open, `Bob's inbox got an OPEN NEEDS_REPLY item (${open?.id})`);

  await bob.emitWithAck('read', { threadId, interactionId: sent.id });
  const done = await pollUntil(async () => {
    const items = await inbox(bobToken);
    const it = items.find((i) => i.id === open.id);
    return it && it.state === 'DONE' ? it : null;
  });
  assert(done, "Bob's item auto-resolved to DONE after reading");

  console.log('\nP3 inbox smoke: PASS');
} finally {
  alice.close();
  bob.close();
}
process.exit(0);
