// P9 slice-3 tenant isolation smoke: two tenants (different orgId, same app) prove
// cross-tenant denial over HTTP. Tenant A schedules a meeting; tenant B cannot read
// it (403) and does not see it in its own list; A reads its own (200).
// Requires the service running with IIOS_DEV_TOKENS=1.
import 'dotenv/config';

const SERVICE = process.env.SMOKE_URL ?? 'http://localhost:3200';
const APP_ID = 'portal-demo';
const assert = (c, m) => { if (!c) { console.error('✗', m); process.exit(1); } console.log('✓', m); };
const START = '2026-07-02T10:00:00.000Z';

async function devToken(userId, orgId) {
  const r = await fetch(`${SERVICE}/v1/dev/token`, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ appId: APP_ID, userId, name: userId, orgId }),
  });
  if (!r.ok) throw new Error(`devToken ${r.status} (service with IIOS_DEV_TOKENS=1?)`);
  return (await r.json()).token;
}
async 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();
}

const A = await devToken('a1', 'org_A');
const B = await devToken('b1', 'org_B');

// A schedules a meeting in tenant A's scope.
const meeting = await json(A, '/v1/calendar/meetings', 'POST', { meetingType: 'INTERNAL', title: 'A only', startAt: START });
assert(meeting.id && meeting.status === 'SCHEDULED', 'tenant A scheduled a meeting');

// B cannot read A's meeting by id.
const bGet = await call(B, `/v1/calendar/meetings/${meeting.id}`);
assert(bGet.status === 403, `tenant B reading A's meeting → 403 (got ${bGet.status}) — KG-02`);

// B's own list does not include A's meeting.
const bList = await json(B, '/v1/calendar/meetings');
assert(!bList.some((m) => m.id === meeting.id), "tenant B's meeting list excludes A's meeting");

// A reads its own meeting fine (same-tenant control).
const aGet = await json(A, `/v1/calendar/meetings/${meeting.id}`);
assert(aGet.id === meeting.id, 'same-tenant read succeeds (200)');

console.log('\nP9 tenant isolation smoke: PASS');
process.exit(0);
