// v1.1 smoke: dev IdP login, policy-enforced DM cap / group membership, listThreads,
// and threaded replies — all over REST. Requires the service with IIOS_DEV_TOKENS=1.
import 'dotenv/config';

const SERVICE = process.env.SMOKE_URL ?? 'http://localhost:3200';
const assert = (c, m) => { if (!c) { console.error('✗', m); process.exit(1); } console.log('✓', m); };

async function login(username, password) {
  const r = await fetch(`${SERVICE}/v1/dev/login`, {
    method: 'POST', headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ username, password }),
  });
  return { status: r.status, body: r.ok ? await r.json() : null };
}
function call(token, path, method = 'GET', body) {
  return fetch(`${SERVICE}${path}`, {
    method,
    headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` },
    body: body ? JSON.stringify(body) : undefined,
  });
}
async function json(token, path, method = 'GET', body) {
  const r = await call(token, path, method, body);
  if (!r.ok) throw new Error(`${method} ${path} ${r.status}: ${await r.text()}`);
  return r.json();
}

// 1) dev IdP: correct password issues a token; wrong password is rejected.
const ok = await login('alice', 'alice');
assert(ok.body?.token, 'dev IdP: alice logs in with password');
const bad = await login('alice', 'nope');
assert(bad.status === 401, 'dev IdP: wrong password → 401');
const alice = ok.body.token;

// 2) DM is capped at two (policy).
const dm = await json(alice, '/v1/threads', 'POST', { membership: 'dm' });
assert(dm.threadId, `alice created a DM (${dm.threadId})`);
const add2 = await json(alice, `/v1/threads/${dm.threadId}/participants`, 'POST', { userId: 'bob' });
assert(add2.participantCount === 2, 'added bob → 2 participants');
const add3 = await call(alice, `/v1/threads/${dm.threadId}/participants`, 'POST', { userId: 'carol' });
assert(add3.status === 403, `adding a 3rd to a DM → 403 policy denied (${add3.status})`);

// 3) group: creator (ADMIN) can add several.
const grp = await json(alice, '/v1/threads', 'POST', { membership: 'group', creatorRole: 'ADMIN' });
await json(alice, `/v1/threads/${grp.threadId}/participants`, 'POST', { userId: 'bob' });
const g3 = await json(alice, `/v1/threads/${grp.threadId}/participants`, 'POST', { userId: 'carol' });
assert(g3.participantCount === 3, 'group admin added bob + carol → 3 participants');

// 4) threaded reply round-trips.
const first = await json(alice, `/v1/threads/${grp.threadId}/messages`, 'POST', { content: 'question?' });
const reply = await json(alice, `/v1/threads/${grp.threadId}/messages`, 'POST', { content: 'answer', parentInteractionId: first.id });
assert(reply.parentInteractionId === first.id, 'a reply carries parentInteractionId');

// 5) listThreads shows the caller's threads with membership + last message.
const mine = await json(alice, '/v1/threads');
const g = mine.find((t) => t.threadId === grp.threadId);
assert(g && g.membership === 'group' && g.participantCount === 3, 'GET /v1/threads lists the group with membership + count');
assert(g.lastMessage === 'answer', 'thread summary carries the last message');

console.log('\nv1.1 membership + replies smoke: PASS');
process.exit(0);
