/**
 * Authentication Helpers for E2E Tests
 * 
 * Shared utilities for authentication testing
 * v0.5.0 - JWT and API Key Authentication Support
 */

import { Page, APIRequestContext, expect } from '@playwright/test';

// Base URLs
const API_BASE_URL = process.env.VITE_API_URL || 'http://localhost:8000/api/v1';
const FRONTEND_URL = process.env.TEST_BASE_URL || 'http://localhost:5173';

// Test user storage for cleanup
const testUsers: { email: string; password: string }[] = [];

/**
 * Register a new user via API
 */
export async function registerUser(
  request: APIRequestContext,
  email: string,
  password: string,
  fullName: string
): Promise<{ user: { id: string; email: string }; access_token: string; refresh_token: string }> {
  const response = await request.post(`${API_BASE_URL}/auth/register`, {
    data: {
      email,
      password,
      full_name: fullName,
    },
  });

  expect(response.ok()).toBeTruthy();
  const data = await response.json();
  
  // Track for cleanup
  testUsers.push({ email, password });
  
  return data;
}

/**
 * Login user via API
 */
export async function loginUser(
  request: APIRequestContext,
  email: string,
  password: string
): Promise<{ access_token: string; refresh_token: string; token_type: string }> {
  const response = await request.post(`${API_BASE_URL}/auth/login`, {
    data: {
      email,
      password,
    },
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Login user via UI
 */
export async function loginUserViaUI(
  page: Page,
  email: string,
  password: string
): Promise<void> {
  await page.goto('/login');
  await page.waitForLoadState('networkidle');

  // Fill login form
  await page.getByLabel(/email/i).fill(email);
  await page.getByLabel(/password/i).fill(password);

  // Submit form
  await page.getByRole('button', { name: /login|sign in/i }).click();

  // Wait for redirect to dashboard
  await page.waitForURL('/', { timeout: 10000 });
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
}

/**
 * Register user via UI
 */
export async function registerUserViaUI(
  page: Page,
  email: string,
  password: string,
  fullName: string
): Promise<void> {
  await page.goto('/register');
  await page.waitForLoadState('networkidle');

  // Fill registration form
  await page.getByLabel(/full name|name/i).fill(fullName);
  await page.getByLabel(/email/i).fill(email);
  await page.getByLabel(/^password$/i).fill(password);
  await page.getByLabel(/confirm password|repeat password/i).fill(password);

  // Submit form
  await page.getByRole('button', { name: /register|sign up|create account/i }).click();

  // Wait for redirect to dashboard
  await page.waitForURL('/', { timeout: 10000 });
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();

  // Track for cleanup
  testUsers.push({ email, password });
}

/**
 * Logout user via UI
 */
export async function logoutUser(page: Page): Promise<void> {
  // Click on user dropdown
  const userDropdown = page.locator('[data-testid="user-dropdown"]').or(
    page.locator('header').getByText(/user|profile|account/i).first()
  );
  
  if (await userDropdown.isVisible().catch(() => false)) {
    await userDropdown.click();
    
    // Click logout
    const logoutButton = page.getByRole('menuitem', { name: /logout|sign out/i }).or(
      page.getByText(/logout|sign out/i).first()
    );
    await logoutButton.click();
  }

  // Wait for redirect to login
  await page.waitForURL('/login', { timeout: 10000 });
}

/**
 * Create authentication header with JWT token
 */
export function createAuthHeader(accessToken: string): { Authorization: string } {
  return {
    Authorization: `Bearer ${accessToken}`,
  };
}

/**
 * Create API Key header
 */
export function createApiKeyHeader(apiKey: string): { 'X-API-Key': string } {
  return {
    'X-API-Key': apiKey,
  };
}

/**
 * Get current user info via API
 */
export async function getCurrentUser(
  request: APIRequestContext,
  accessToken: string
): Promise<{ id: string; email: string; full_name: string }> {
  const response = await request.get(`${API_BASE_URL}/auth/me`, {
    headers: createAuthHeader(accessToken),
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Refresh access token
 */
export async function refreshToken(
  request: APIRequestContext,
  refreshToken: string
): Promise<{ access_token: string; refresh_token: string }> {
  const response = await request.post(`${API_BASE_URL}/auth/refresh`, {
    data: { refresh_token: refreshToken },
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Create an API key via API
 */
export async function createApiKeyViaAPI(
  request: APIRequestContext,
  accessToken: string,
  name: string,
  scopes: string[] = ['read:scenarios'],
  expiresDays?: number
): Promise<{ id: string; name: string; key: string; prefix: string; scopes: string[] }> {
  const data: { name: string; scopes: string[]; expires_days?: number } = {
    name,
    scopes,
  };
  
  if (expiresDays !== undefined) {
    data.expires_days = expiresDays;
  }

  const response = await request.post(`${API_BASE_URL}/api-keys`, {
    data,
    headers: createAuthHeader(accessToken),
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * List API keys via API
 */
export async function listApiKeys(
  request: APIRequestContext,
  accessToken: string
): Promise<Array<{ id: string; name: string; prefix: string; scopes: string[]; is_active: boolean }>> {
  const response = await request.get(`${API_BASE_URL}/api-keys`, {
    headers: createAuthHeader(accessToken),
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Revoke API key via API
 */
export async function revokeApiKey(
  request: APIRequestContext,
  accessToken: string,
  apiKeyId: string
): Promise<void> {
  const response = await request.delete(`${API_BASE_URL}/api-keys/${apiKeyId}`, {
    headers: createAuthHeader(accessToken),
  });

  expect(response.ok()).toBeTruthy();
}

/**
 * Validate API key via API
 */
export async function validateApiKey(
  request: APIRequestContext,
  apiKey: string
): Promise<boolean> {
  const response = await request.get(`${API_BASE_URL}/auth/me`, {
    headers: createApiKeyHeader(apiKey),
  });

  return response.ok();
}

/**
 * Generate unique test email
 */
export function generateTestEmail(prefix = 'test'): string {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 8);
  return `${prefix}.${timestamp}.${random}@test.mockupaws.com`;
}

/**
 * Generate unique test user data
 */
export function generateTestUser(prefix = 'Test'): { 
  email: string; 
  password: string; 
  fullName: string;
} {
  const timestamp = Date.now();
  return {
    email: `user.${timestamp}@test.mockupaws.com`,
    password: 'TestPassword123!',
    fullName: `${prefix} User ${timestamp}`,
  };
}

/**
 * Clear all test users (cleanup function)
 */
export async function cleanupTestUsers(request: APIRequestContext): Promise<void> {
  for (const user of testUsers) {
    try {
      // Try to login and delete user (if API supports it)
      const loginResponse = await request.post(`${API_BASE_URL}/auth/login`, {
        data: { email: user.email, password: user.password },
      });

      if (loginResponse.ok()) {
        const { access_token } = await loginResponse.json();
        // Delete user - endpoint may vary
        await request.delete(`${API_BASE_URL}/auth/me`, {
          headers: createAuthHeader(access_token),
        });
      }
    } catch {
      // Ignore cleanup errors
    }
  }
  testUsers.length = 0;
}

/**
 * Check if user is authenticated on the page
 */
export async function isAuthenticated(page: Page): Promise<boolean> {
  // Check for user dropdown or authenticated state indicators
  const userDropdown = page.locator('[data-testid="user-dropdown"]');
  const logoutButton = page.getByRole('button', { name: /logout/i });
  
  const hasUserDropdown = await userDropdown.isVisible().catch(() => false);
  const hasLogoutButton = await logoutButton.isVisible().catch(() => false);
  
  return hasUserDropdown || hasLogoutButton;
}

/**
 * Wait for auth redirect
 */
export async function waitForAuthRedirect(page: Page, expectedPath: string = '/login'): Promise<void> {
  await page.waitForURL(expectedPath, { timeout: 5000 });
}

/**
 * Set local storage token (for testing protected routes)
 */
export async function setAuthToken(page: Page, token: string): Promise<void> {
  await page.evaluate((t) => {
    localStorage.setItem('access_token', t);
  }, token);
}

/**
 * Clear local storage token
 */
export async function clearAuthToken(page: Page): Promise<void> {
  await page.evaluate(() => {
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
  });
}
