// smoke: permission admin endpoints (Bearer + Casbin RBAC required)
//
// Goal: verify each route is wired and rejects a non-admin caller. Full happy-
// path admin testing lives in journeys/rbac_admin.js (requires seeded admin).
//
// Covers (12 endpoints, mostly negative since the test user has no admin role):
//   GET    /api/v1/permissions/roles
//   POST   /api/v1/permissions/roles
//   PATCH  /api/v1/permissions/roles/:id
//   DELETE /api/v1/permissions/roles/:id
//   GET    /api/v1/permissions/roles/:id/permissions
//   PUT    /api/v1/permissions/roles/:id/permissions
//   GET    /api/v1/permissions/users/:uid/roles
//   POST   /api/v1/permissions/users/:uid/roles
//   DELETE /api/v1/permissions/users/:uid/roles/:role_id
//   GET    /api/v1/permissions/role-mappings
//   PUT    /api/v1/permissions/role-mappings
//   DELETE /api/v1/permissions/role-mappings
//   POST   /api/v1/permissions/policy/reload
//
// Each call is expected to return 403 (RBAC) — we just need to confirm the
// status is non-2xx and the route exists (no 404).
import { get, post, put, patch, del } from '../lib/http.js';
import { check } from 'k6';
import { registerAndConfirm } from '../lib/auth.js';

export const options = {
  vus: 1,
  iterations: 1,
  thresholds: { checks: ['rate==1.0'] },
};

function assertForbidden(res, label) {
  // Casbin reject → 403 (31507000 forbidden). We tolerate 401/403 here since
  // the exact code may vary across edge cases (missing role vs RBAC denied).
  const ok = check(res, {
    [`${label}: route exists (not 404)`]: (r) => r.status !== 404,
    [`${label}: non-2xx (RBAC blocks)`]: (r) => r.status >= 400 && r.status < 500,
  });
  if (!ok) {
    throw new Error(`${label}: unexpected status ${res.status} body=${res.body}`);
  }
}

export default function () {
  const { tokens } = registerAndConfirm();
  const bearer = { Authorization: `Bearer ${tokens.access_token}` };
  const fakeID = '000000000000000000000000';

  assertForbidden(get('/api/v1/permissions/roles', bearer), 'GET /roles');
  assertForbidden(post('/api/v1/permissions/roles', { key: 'smoke_role' }, bearer), 'POST /roles');
  assertForbidden(patch(`/api/v1/permissions/roles/${fakeID}`, { display_name: 'x' }, bearer), 'PATCH /roles/:id');
  assertForbidden(del(`/api/v1/permissions/roles/${fakeID}`, null, bearer), 'DELETE /roles/:id');
  assertForbidden(get(`/api/v1/permissions/roles/${fakeID}/permissions`, bearer), 'GET /roles/:id/permissions');
  assertForbidden(put(`/api/v1/permissions/roles/${fakeID}/permissions`, { permission_ids: [] }, bearer), 'PUT /roles/:id/permissions');
  assertForbidden(get(`/api/v1/permissions/users/${tokens.uid}/roles`, bearer), 'GET /users/:uid/roles');
  assertForbidden(post(`/api/v1/permissions/users/${tokens.uid}/roles`, { role_id: fakeID }, bearer), 'POST /users/:uid/roles');
  assertForbidden(del(`/api/v1/permissions/users/${tokens.uid}/roles/${fakeID}`, null, bearer), 'DELETE /users/:uid/roles/:role_id');
  assertForbidden(get('/api/v1/permissions/role-mappings', bearer), 'GET /role-mappings');
  assertForbidden(put('/api/v1/permissions/role-mappings', {
    external_source: 'zitadel',
    external_key: 'smoke',
    internal_role_key: 'platform_admin',
  }, bearer), 'PUT /role-mappings');
  assertForbidden(del('/api/v1/permissions/role-mappings', {
    external_source: 'zitadel',
    external_key: 'smoke',
  }, bearer), 'DELETE /role-mappings');
  assertForbidden(post('/api/v1/permissions/policy/reload', {}, bearer), 'POST /policy/reload');
}
