/**
 * EN: k6 load test — SignalR connection simulation via HTTP negotiation endpoint.
 * VI: k6 load test — mô phỏng kết nối SignalR qua endpoint negotiation HTTP.
 *
 * EN: SignalR long-polling / SSE fallback test. WebSocket tests require k6 ws module.
 * VI: Test long-polling / SSE fallback. Test WebSocket cần module k6 ws.
 *
 * EN: Tests the /hubs/pos/negotiate endpoint which is the SignalR handshake.
 * VI: Test endpoint /hubs/pos/negotiate là bắt tay SignalR.
 *
 * Usage:
 *   k6 run tests/load/k6/signalr-connections.js
 *   k6 run --env BASE_URL=http://api.staging.goodgo.vn tests/load/k6/signalr-connections.js
 *
 * Thresholds:
 *   - 95th-percentile negotiation < 300ms
 *   - Concurrent connections > 200 without errors
 */
import http from 'k6/http';
import ws from 'k6/ws';
import { check, sleep } from 'k6';
import { Rate, Trend, Counter, Gauge } from 'k6/metrics';

// ---------------------------------------------------------------------------
// Custom metrics
// ---------------------------------------------------------------------------
const negotiationErrors = new Rate('signalr_negotiation_errors');
const negotiationDuration = new Trend('signalr_negotiation_duration', true);
const activeConnections = new Gauge('signalr_active_connections');
const messagesReceived = new Counter('signalr_messages_received');

// ---------------------------------------------------------------------------
// Test options
// ---------------------------------------------------------------------------
export const options = {
  scenarios: {
    // EN: Scenario 1 — HTTP negotiation endpoint load / VI: Tình huống 1 — load endpoint negotiation
    negotiation_load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '30s', target: 50 },
        { duration: '1m', target: 100 },
        { duration: '30s', target: 200 },
        { duration: '30s', target: 0 },
      ],
      exec: 'testNegotiation',
    },
    // EN: Scenario 2 — Concurrent WebSocket connections / VI: Tình huống 2 — kết nối WebSocket đồng thời
    websocket_connections: {
      executor: 'constant-vus',
      vus: 50,
      duration: '2m',
      startTime: '30s',
      exec: 'testWebSocketConnection',
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<300'],
    signalr_negotiation_errors: ['rate<0.01'],
    signalr_negotiation_duration: ['p(95)<300'],
  },
};

// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5010';
const WS_URL = __ENV.WS_URL || 'ws://localhost:5010';
const JWT_TOKEN = __ENV.JWT_TOKEN || 'test-bearer-token';
const SHOP_ID = __ENV.SHOP_ID || '00000000-0000-0000-0000-000000000001';

const headers = {
  Authorization: `Bearer ${JWT_TOKEN}`,
  'X-Shop-Id': SHOP_ID,
};

// ---------------------------------------------------------------------------
// Scenario 1: HTTP negotiation endpoint
// ---------------------------------------------------------------------------
export function testNegotiation() {
  const res = http.post(
    `${BASE_URL}/hubs/pos/negotiate?negotiateVersion=1`,
    null,
    { headers }
  );

  negotiationDuration.add(res.timings.duration);

  const ok = check(res, {
    'negotiate status 200': (r) => r.status === 200,
    'negotiate returns connectionToken': (r) => {
      try {
        const body = JSON.parse(r.body);
        return body.connectionToken !== undefined || body.connectionId !== undefined;
      } catch {
        // EN: May return 401 in load env without valid token — still a valid response
        // VI: Có thể trả 401 trong load env không có token hợp lệ
        return r.status < 500;
      }
    },
    'negotiate < 300ms': (r) => r.timings.duration < 300,
  });

  negotiationErrors.add(ok ? 0 : 1);
  sleep(1 + Math.random() * 2);
}

// ---------------------------------------------------------------------------
// Scenario 2: WebSocket connection lifecycle
// ---------------------------------------------------------------------------
export function testWebSocketConnection() {
  const wsUrl = `${WS_URL}/hubs/pos?access_token=${JWT_TOKEN}&shopId=${SHOP_ID}`;

  const res = ws.connect(wsUrl, {}, (socket) => {
    activeConnections.add(1);

    socket.on('open', () => {
      // EN: Send SignalR handshake message / VI: Gửi tin handshake SignalR
      socket.send(JSON.stringify({ protocol: 'json', version: 1 }) + '\x1e');
    });

    socket.on('message', (msg) => {
      messagesReceived.add(1);
      // EN: Keep connection alive for 5s then close / VI: Giữ kết nối 5s rồi đóng
    });

    socket.on('error', () => {
      negotiationErrors.add(1);
    });

    // EN: Hold connection for 5 seconds to simulate active POS session
    // VI: Giữ kết nối 5 giây để mô phỏng phiên POS đang hoạt động
    socket.setTimeout(() => {
      socket.close();
    }, 5000);
  });

  activeConnections.add(-1);

  check(res, {
    'ws connected or 401': () => res.status === 101 || res.status === 401,
  });

  sleep(1);
}
