/**
 * tapper — Failover / Resilience Test
 *
 * Validates the platform's ability to survive an API instance failure.
 * tapper runs two API instances (api-1, api-2) behind Traefik.
 * This test sustains steady load while you manually kill one instance,
 * then measures the error spike and recovery time.
 *
 * Test plan:
 *   Phase 1 (0:00 – 0:45)  — Baseline: 50 VUs, both instances healthy
 *   Phase 2 (0:45 – 1:15)  — KILL api-2 during this window
 *   Phase 3 (1:15 – 2:30)  — Recovery: measure how quickly errors drop
 *   Phase 4 (2:30 – 3:00)  — Cool-down
 *
 * How to run:
 *   Terminal 1:  k6 run loadtest/failover-test.js
 *   Terminal 2:  (at ~45s) docker stop tapper-api-2
 *   Terminal 2:  (at ~90s, optional) docker start tapper-api-2
 *
 * Run with JSON output for detailed analysis:
 *   k6 run --out json=loadtest/results/failover.json loadtest/failover-test.js
 */

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

// ── Custom metrics ──────────────────────────────────────────────────────────
const failoverErrors = new Counter('failover_errors');
const failoverSuccess = new Rate('failover_success_rate');
const requestDuration = new Trend('failover_req_duration', true);
const authErrors = new Counter('failover_auth_errors');
const profileErrors = new Counter('failover_profile_errors');

// ── k6 options ──────────────────────────────────────────────────────────────
export const options = {
  scenarios: {
    failover: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '15s', target: 50 },   // ramp to target
        { duration: '30s', target: 50 },   // baseline measurement
        { duration: '30s', target: 50 },   // ← KILL api-2 here
        { duration: '1m15s', target: 50 }, // recovery observation
        { duration: '30s', target: 0 },    // cool-down
      ],
      gracefulRampDown: '10s',
    },
  },
  thresholds: {
    // During failover we expect some errors, but the system should recover.
    // Overall error rate should stay under 10 % across the full test.
    http_req_failed: [
      { threshold: 'rate<0.10', abortOnFail: false },
    ],
    // We do NOT abort on high error rate because transient spikes are expected.
    failover_success_rate: [
      { threshold: 'rate>0.80', abortOnFail: false },
    ],
  },
};

// ── Pre-registered credentials cache ────────────────────────────────────────
// During failover, registration may fail. We cache successful credentials
// so VUs can fall back to re-login instead of re-register.
const vuCredentials = {};

// ── Setup ───────────────────────────────────────────────────────────────────
export function setup() {
  const BASE_URL = getBaseUrl();
  const res = http.get(`${BASE_URL}/api/health`);
  const ok = check(res, {
    'setup: server healthy': (r) => r.status === 200,
  });
  if (!ok) {
    console.error('Server not healthy. Cannot run failover test.');
    return { abort: true };
  }

  console.log('');
  console.log('╔══════════════════════════════════════════════════════════╗');
  console.log('║              FAILOVER TEST INSTRUCTIONS                 ║');
  console.log('╠══════════════════════════════════════════════════════════╣');
  console.log('║                                                        ║');
  console.log('║  1. Watch this test run for ~45 seconds (baseline)     ║');
  console.log('║  2. In another terminal, run:                          ║');
  console.log('║       docker stop tapper-api-2                         ║');
  console.log('║  3. Observe the error spike in real-time               ║');
  console.log('║  4. (Optional) After ~30s, restart:                    ║');
  console.log('║       docker start tapper-api-2                        ║');
  console.log('║  5. Watch recovery metrics                             ║');
  console.log('║                                                        ║');
  console.log('╚══════════════════════════════════════════════════════════╝');
  console.log('');

  return { baseUrl: BASE_URL };
}

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

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

  // ── Obtain authentication ───────────────────────────────────────────────
  group('failover: authenticate', () => {
    // Try cached credentials first (faster, avoids register during outage)
    if (vuCredentials[__VU]) {
      const creds = vuCredentials[__VU];
      token = loginUser(creds.email, creds.password);
      if (token) {
        failoverSuccess.add(true);
        return;
      }
      // Login failed — try fresh registration
    }

    // Fresh registration + login
    const result = registerAndLogin();
    token = result.token;

    if (token) {
      // Cache for re-use in subsequent iterations
      vuCredentials[__VU] = {
        email: result.email,
        password: result.password,
      };
      failoverSuccess.add(true);
    } else {
      authErrors.add(1);
      failoverErrors.add(1);
      failoverSuccess.add(false);
    }
  });

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

  sleep(0.3);

  // ── Profile fetch (primary measurement endpoint) ────────────────────────
  group('failover: profile', () => {
    const res = authGet('/api/profile', token, { name: 'GET /api/profile' });
    requestDuration.add(res.timings.duration);

    const ok = check(res, {
      'profile: status 200': (r) => r.status === 200,
    });

    if (ok) {
      failoverSuccess.add(true);
    } else {
      profileErrors.add(1);
      failoverErrors.add(1);
      failoverSuccess.add(false);
    }
  });

  sleep(0.3);

  // ── Leaderboard (read-only, good canary) ────────────────────────────────
  group('failover: leaderboard', () => {
    const res = authGet('/api/leaderboard', token, { name: 'GET /api/leaderboard' });
    requestDuration.add(res.timings.duration);

    const ok = check(res, {
      'leaderboard: status 200': (r) => r.status === 200,
    });
    failoverSuccess.add(ok);
    if (!ok) failoverErrors.add(1);
  });

  sleep(0.3);

  // ── Match history ───────────────────────────────────────────────────────
  group('failover: matches', () => {
    const res = authGet('/api/matches', token, { name: 'GET /api/matches' });
    requestDuration.add(res.timings.duration);

    const ok = check(res, {
      'matches: status 200': (r) => r.status === 200,
    });
    failoverSuccess.add(ok);
    if (!ok) failoverErrors.add(1);
  });

  sleep(0.5);

  // ── Health check (direct instance monitoring) ───────────────────────────
  group('failover: health', () => {
    const res = http.get(`${BASE_URL}/api/health`, {
      tags: { name: 'GET /api/health' },
    });
    requestDuration.add(res.timings.duration);

    check(res, {
      'health: status 200': (r) => r.status === 200,
    });
  });

  sleep(0.5);
}

// ── Teardown ────────────────────────────────────────────────────────────────
export function teardown(data) {
  console.log('');
  console.log('=== FAILOVER TEST ANALYSIS ===');
  console.log('');
  console.log('Key metrics to compare BEFORE vs AFTER killing api-2:');
  console.log('');
  console.log('  1. failover_errors        — Total errors during the test');
  console.log('  2. failover_success_rate   — Should stay >80% overall');
  console.log('  3. failover_req_duration   — Compare p50/p95 before/after');
  console.log('  4. failover_auth_errors    — Auth failures during outage');
  console.log('  5. failover_profile_errors — Profile fetch failures');
  console.log('');
  console.log('Recovery analysis:');
  console.log('  - If using JSON output (--out json=file.json), plot');
  console.log('    error rate over time to measure recovery duration.');
  console.log('  - Traefik should detect the downed instance within ~10s');
  console.log('    and route all traffic to the healthy instance.');
  console.log('  - Expected recovery time: <15 seconds.');
  console.log('');
  console.log('If you restarted api-2 during the test:');
  console.log('  - Traefik should re-add it to the pool within ~10-30s');
  console.log('  - Throughput should return to pre-failure levels');
  console.log('');
  console.log('Reminder: make sure api-2 is running after the test:');
  console.log('  docker start tapper-api-2');
}
