import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
import { randomString } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

// Load environment variables
const API_ORIGIN = __ENV.API_ORIGIN || 'https://api.lab.veza';
const TEST_EMAIL_PREFIX = __ENV.TEST_EMAIL_PREFIX || 'user+perf';
const TEST_EMAIL_DOMAIN = __ENV.TEST_EMAIL_DOMAIN || 'lab.veza';
const TEST_PASSWORD_PREFIX = __ENV.TEST_PASSWORD_PREFIX || 'V3za!perf-';

// Custom metrics
const loginDuration = new Trend('login_duration');
const loginFailureRate = new Rate('login_failures');
const registerDuration = new Trend('register_duration');
const registerFailureRate = new Rate('register_failures');

// Test configuration
export const options = {
  scenarios: {
    auth_flow: {
      executor: 'ramping-vus',
      stages: [
        { duration: '30s', target: 5 },   // Ramp up to 5 users
        { duration: '1m', target: 10 },   // Stay at 10 users
        { duration: '30s', target: 0 },   // Ramp down
      ],
      gracefulRampDown: '30s',
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<300', 'p(99)<500'], // 95% of requests under 300ms
    login_duration: ['p(95)<300', 'p(99)<500'],
    register_duration: ['p(95)<800', 'p(99)<1000'],
    login_failures: ['rate<0.1'],   // Less than 10% failure rate
    register_failures: ['rate<0.1'],
    http_req_failed: ['rate<0.1'],  // Overall error rate under 10%
  },
};

// Helper to generate unique test user
function generateTestUser() {
  const rand = randomString(8);
  return {
    email: `${TEST_EMAIL_PREFIX}${rand}@${TEST_EMAIL_DOMAIN}`,
    password: `${TEST_PASSWORD_PREFIX}${rand}`,
  };
}

// Setup: Create some test users
export function setup() {
  const users = [];
  
  console.log('Creating test users for performance test...');
  
  for (let i = 0; i < 20; i++) {
    const user = generateTestUser();
    const registerPayload = JSON.stringify(user);
    
    const registerRes = http.post(`${API_ORIGIN}/auth/register`, registerPayload, {
      headers: { 'Content-Type': 'application/json' },
    });
    
    if (registerRes.status === 201) {
      users.push(user);
    }
  }
  
  console.log(`Created ${users.length} test users`);
  return { users };
}

export default function (data) {
  const { users } = data;
  
  // Pick a random user from the pool
  const user = users[Math.floor(Math.random() * users.length)];
  
  // Test 1: Login with valid credentials
  const loginPayload = JSON.stringify({
    email: user.email,
    password: user.password,
  });
  
  const loginStart = new Date();
  const loginRes = http.post(`${API_ORIGIN}/auth/login`, loginPayload, {
    headers: { 'Content-Type': 'application/json' },
    tags: { name: 'login' },
  });
  const loginEnd = new Date();
  
  // Record metrics
  loginDuration.add(loginEnd - loginStart);
  loginFailureRate.add(loginRes.status !== 200);
  
  // Validate response
  check(loginRes, {
    'login status is 200': (r) => r.status === 200,
    'login has access_token': (r) => {
      try {
        const body = JSON.parse(r.body);
        return body.access_token !== undefined;
      } catch {
        return false;
      }
    },
    'login has refresh_token': (r) => {
      try {
        const body = JSON.parse(r.body);
        return body.refresh_token !== undefined;
      } catch {
        return false;
      }
    },
    'login response time < 300ms': (r) => r.timings.duration < 300,
  });
  
  // Extract tokens if successful
  let accessToken = '';
  if (loginRes.status === 200) {
    try {
      const body = JSON.parse(loginRes.body);
      accessToken = body.access_token;
    } catch (e) {
      console.error('Failed to parse login response');
    }
  }
  
  sleep(1); // Think time
  
  // Test 2: Access protected endpoint
  if (accessToken) {
    const meRes = http.get(`${API_ORIGIN}/me`, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
      },
      tags: { name: 'get_profile' },
    });
    
    check(meRes, {
      'profile status is 200': (r) => r.status === 200,
      'profile has user data': (r) => {
        try {
          const body = JSON.parse(r.body);
          return body.id !== undefined && body.email !== undefined;
        } catch {
          return false;
        }
      },
      'profile response time < 200ms': (r) => r.timings.duration < 200,
    });
  }
  
  sleep(1);
  
  // Test 3: Try invalid login (10% of time)
  if (Math.random() < 0.1) {
    const invalidLoginPayload = JSON.stringify({
      email: user.email,
      password: 'WrongPassword123!',
    });
    
    const invalidLoginRes = http.post(`${API_ORIGIN}/auth/login`, invalidLoginPayload, {
      headers: { 'Content-Type': 'application/json' },
      tags: { name: 'login_invalid' },
    });
    
    check(invalidLoginRes, {
      'invalid login returns 401': (r) => r.status === 401,
    });
  }
  
  sleep(1);
  
  // Test 4: Token refresh (if we have a refresh token)
  if (loginRes.status === 200) {
    try {
      const body = JSON.parse(loginRes.body);
      const refreshToken = body.refresh_token;
      
      if (refreshToken) {
        const refreshPayload = JSON.stringify({ refresh_token: refreshToken });
        const refreshRes = http.post(`${API_ORIGIN}/auth/refresh`, refreshPayload, {
          headers: { 'Content-Type': 'application/json' },
          tags: { name: 'token_refresh' },
        });
        
        check(refreshRes, {
          'refresh status is 200': (r) => r.status === 200,
          'refresh has new tokens': (r) => {
            try {
              const refreshBody = JSON.parse(r.body);
              return refreshBody.access_token !== undefined;
            } catch {
              return false;
            }
          },
          'refresh response time < 200ms': (r) => r.timings.duration < 200,
        });
      }
    } catch (e) {
      console.error('Failed to test token refresh');
    }
  }
  
  sleep(2); // Think time between iterations
}

// Teardown: Clean up test users (optional)
export function teardown(data) {
  console.log('Performance test completed');
  console.log(`Total users tested: ${data.users.length}`);
  
  // In a real scenario, you might want to delete the test users
  // But for now, we'll leave them for potential debugging
}