/**
 * k6 load test — Credential Rotation
 *
 * Scenario : POST /api/v1/agents/:agentId/credentials/:credentialId/rotate
 * VUs      : 50
 * Duration : 60 seconds
 * Thresholds:
 *   p95 response time < 500 ms
 *   HTTP error rate   < 1 %
 *
 * Usage:
 *   BASE_URL=http://localhost:3000  \
 *   AGENT_ID=your-agent-id          \
 *   ACCESS_TOKEN=your-access-token  \
 *   k6 run tests/load/credential-rotation.js
 *
 * Note: This test requires a pre-provisioned agent with at least one active
 * credential. The AGENT_ID and ACCESS_TOKEN must be set before running.
 * If CREDENTIAL_ID is not set, the test uses the "active" credential alias.
 */

import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';

// ── Custom metrics ─────────────────────────────────────────────────────────────
const errorRate = new Rate('error_rate');
const rotationDuration = new Trend('rotation_duration_ms', true);

// ── Configuration ──────────────────────────────────────────────────────────────
export const options = {
  vus: 50,
  duration: '60s',
  thresholds: {
    http_req_duration: ['p(95)<500'],
    error_rate: ['rate<0.01'],
  },
};

const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000';
const AGENT_ID = __ENV.AGENT_ID || 'load-test-agent-id';
const CREDENTIAL_ID = __ENV.CREDENTIAL_ID || 'active';
const ACCESS_TOKEN = __ENV.ACCESS_TOKEN || 'load-test-token';

// ── Setup: issue an access token once per test run ────────────────────────────
export function setup() {
  // If an ACCESS_TOKEN was provided, skip token issuance.
  if (ACCESS_TOKEN !== 'load-test-token') {
    return { token: ACCESS_TOKEN };
  }

  const tokenUrl = `${BASE_URL}/api/v1/token`;
  const tokenPayload = {
    grant_type: 'client_credentials',
    client_id: __ENV.CLIENT_ID || '',
    client_secret: __ENV.CLIENT_SECRET || '',
    scope: 'credentials:write',
  };
  const tokenRes = http.post(tokenUrl, tokenPayload, {
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  });

  if (tokenRes.status !== 200) {
    console.warn(`Setup token issuance failed: ${tokenRes.status} — using env ACCESS_TOKEN`);
    return { token: ACCESS_TOKEN };
  }

  const tokenBody = JSON.parse(tokenRes.body);
  return { token: tokenBody.access_token };
}

// ── Default function (executed per VU iteration) ───────────────────────────────
export default function credentialRotation(data) {
  const { token } = data;
  const url = `${BASE_URL}/api/v1/agents/${AGENT_ID}/credentials/${CREDENTIAL_ID}/rotate`;

  const params = {
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    timeout: '10s',
  };

  const response = http.post(url, null, params);

  rotationDuration.add(response.timings.duration);

  const success = check(response, {
    'status is 200 or 201': (r) => r.status === 200 || r.status === 201,
    'response has new credential': (r) => {
      // 401/403 from misconfigured env vars counts as an infrastructure issue,
      // not an application error, so we only fail on 5xx.
      if (r.status === 401 || r.status === 403) {
        console.warn(`Auth error ${r.status} — check ACCESS_TOKEN / AGENT_ID env vars`);
        return true; // do not inflate error rate for config issues
      }
      if (r.status >= 500) {
        return false;
      }
      try {
        const body = JSON.parse(r.body);
        return typeof body.credentialId === 'string' || typeof body.id === 'string';
      } catch {
        return false;
      }
    },
    'response time < 500ms': (r) => r.timings.duration < 500,
  });

  errorRate.add(!success);

  // Think-time between rotations — credential rotation is a lower-frequency op
  sleep(0.2);
}
