/**
 * tapper — Stress Test
 *
 * Progressively increases load to find the breaking point.
 * Ramps from 10 → 200+ VUs over ~3 minutes, monitoring when errors
 * start appearing and latency degrades.
 *
 * Expected bottleneck: PostgreSQL connection pool exhaustion when both
 * API instances compete for connections under high concurrency.
 *
 * Stages:
 *   0  → 10 VUs   (15 s)  — baseline
 *   10 → 50 VUs   (30 s)  — moderate
 *   50 → 100 VUs  (30 s)  — heavy
 *   100 → 200 VUs (30 s)  — stress
 *   200 → 250 VUs (30 s)  — breaking point
 *   250 VUs       (30 s)  — sustained peak
 *   250 → 0 VUs   (15 s)  — cool-down
 *
 * Run:  k6 run loadtest/stress-test.js
 */

import http from 'k6/http';
import { check, group, sleep } from 'k6';
import { Counter, Rate, Trend } from 'k6/metrics';
import {
  registerAndLogin,
  authGet,
  authPost,
  getBaseUrl,
} from './helpers/auth.js';

// ── Custom metrics ──────────────────────────────────────────────────────────
const errorCount = new Counter('stress_errors');
const successRate = new Rate('stress_success_rate');
const authDuration = new Trend('stress_auth_duration', true);
const profileDuration = new Trend('stress_profile_duration', true);
const queueDuration = new Trend('stress_queue_duration', true);

// ── k6 options ──────────────────────────────────────────────────────────────
export const options = {
  scenarios: {
    stress: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '15s', target: 10 },    // baseline
        { duration: '30s', target: 50 },    // moderate load
        { duration: '30s', target: 100 },   // heavy load
        { duration: '30s', target: 200 },   // stress zone
        { duration: '30s', target: 250 },   // push toward breaking point
        { duration: '30s', target: 250 },   // sustained peak
        { duration: '15s', target: 0 },     // cool-down
      ],
      gracefulRampDown: '10s',
    },
  },
  thresholds: {
    // Intentionally lenient — we WANT to see failures to find the breaking point.
    // These thresholds exist to flag but not abort the test.
    http_req_duration: [
      { threshold: 'p(95)<1000', abortOnFail: false },
      { threshold: 'p(99)<3000', abortOnFail: false },
    ],
    http_req_failed: [
      { threshold: 'rate<0.10', abortOnFail: false },  // warn at 10 %
      { threshold: 'rate<0.50', abortOnFail: true },    // abort at 50 % (server down)
    ],
    stress_success_rate: [
      { threshold: 'rate>0.50', abortOnFail: true },
    ],
  },
};

// ── Setup ───────────────────────────────────────────────────────────────────
export function setup() {
  const BASE_URL = getBaseUrl();
  const res = http.get(`${BASE_URL}/api/health`);
  const ok = check(res, {
    'setup: server reachable': (r) => r.status === 200,
  });
  if (!ok) {
    console.error('Server not reachable. Aborting stress test.');
    return { abort: true };
  }
  console.log('Stress test starting. Watch for error spikes as VUs increase.');
  console.log('Expected bottleneck: DB connection pool at ~150-200 VUs.');
  return { baseUrl: BASE_URL };
}

// ── Main VU function ────────────────────────────────────────────────────────
export default function (data) {
  if (data && data.abort) {
    return;
  }

  const BASE_URL = getBaseUrl();
  let token = null;

  // ── Auth flow ───────────────────────────────────────────────────────────
  group('stress: auth', () => {
    const start = Date.now();
    const result = registerAndLogin();
    authDuration.add(Date.now() - start);
    token = result.token;

    if (!token) {
      errorCount.add(1);
      successRate.add(false);
      return;
    }
    successRate.add(true);
  });

  if (!token) {
    sleep(0.5);
    return;
  }

  sleep(0.2);

  // ── Profile fetch ───────────────────────────────────────────────────────
  group('stress: profile', () => {
    const res = authGet('/api/profile', token, { name: 'GET /api/profile' });
    profileDuration.add(res.timings.duration);

    const ok = check(res, {
      'profile: status 200': (r) => r.status === 200,
    });
    successRate.add(ok);
    if (!ok) errorCount.add(1);
  });

  sleep(0.2);

  // ── Leaderboard ─────────────────────────────────────────────────────────
  group('stress: leaderboard', () => {
    const res = authGet('/api/leaderboard', token, { name: 'GET /api/leaderboard' });
    const ok = check(res, {
      'leaderboard: status 200': (r) => r.status === 200,
    });
    successRate.add(ok);
    if (!ok) errorCount.add(1);
  });

  sleep(0.2);

  // ── Queue join → status → leave ────────────────────────────────────────
  group('stress: queue cycle', () => {
    const joinRes = authPost('/api/queue/join', {}, token, { name: 'POST /api/queue/join' });
    queueDuration.add(joinRes.timings.duration);

    const joinOk = check(joinRes, {
      'queue join: accepted': (r) =>
        r.status === 200 || r.status === 201 || r.status === 409,
    });
    successRate.add(joinOk);
    if (!joinOk) errorCount.add(1);

    sleep(0.2);

    const statusRes = authGet('/api/queue/status', token, { name: 'GET /api/queue/status' });
    check(statusRes, {
      'queue status: ok': (r) => r.status === 200,
    });

    // Leave queue to avoid orphaned entries
    authPost('/api/queue/leave', {}, token, { name: 'POST /api/queue/leave' });
  });

  sleep(0.2);

  // ── Match history ───────────────────────────────────────────────────────
  group('stress: matches', () => {
    const res = authGet('/api/matches', token, { name: 'GET /api/matches' });
    const ok = check(res, {
      'matches: status 200': (r) => r.status === 200,
    });
    successRate.add(ok);
    if (!ok) errorCount.add(1);
  });

  sleep(0.3);
}

// ── Teardown ────────────────────────────────────────────────────────────────
export function teardown(data) {
  console.log('');
  console.log('=== STRESS TEST ANALYSIS GUIDE ===');
  console.log('');
  console.log('Look for these signals in the output above:');
  console.log('  1. At which VU count did http_req_failed start rising?');
  console.log('     (Check the "stress_errors" counter timeline)');
  console.log('  2. When did p95 latency exceed 500ms? 1000ms? 3000ms?');
  console.log('  3. Did the test abort early due to >50% error rate?');
  console.log('');
  console.log('Common bottlenecks:');
  console.log('  - DB connection pool: errors spike suddenly at a threshold');
  console.log('  - CPU saturation: latency climbs linearly with VU count');
  console.log('  - Memory pressure: errors after sustained high load');
  console.log('');
  console.log('Recommended next step: run with --out json=results.json');
  console.log('for detailed timeline analysis.');
}
