/**
 * QA-AUTH-019: Authentication Tests
 * 
 * E2E Test Suite for Authentication Flow
 * - Registration
 * - Login
 * - Protected Routes
 * - Logout
 */

import { test, expect } from '@playwright/test';
import { navigateTo, waitForLoading } from './utils/test-helpers';
import {
  generateTestEmail,
  generateTestUser,
  loginUserViaUI,
  registerUserViaUI,
  logoutUser,
  isAuthenticated,
  waitForAuthRedirect,
  clearAuthToken,
} from './utils/auth-helpers';

// ============================================
// TEST SUITE: Registration
// ============================================
test.describe('QA-AUTH-019: Registration', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/register');
    await page.waitForLoadState('networkidle');
  });

  test('should register new user successfully', async ({ page }) => {
    const testUser = generateTestUser('Registration');

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

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

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

    // Verify user is authenticated
    expect(await isAuthenticated(page)).toBe(true);
  });

  test('should show error for duplicate email', async ({ page, request }) => {
    const testEmail = generateTestEmail('duplicate');
    const testUser = generateTestUser();

    // Register first user
    await registerUserViaUI(page, testEmail, testUser.password, testUser.fullName);

    // Logout and try to register again with same email
    await logoutUser(page);
    await page.goto('/register');
    await page.waitForLoadState('networkidle');

    // Fill form with same email
    await page.getByLabel(/full name|name/i).fill('Another Name');
    await page.getByLabel(/email/i).fill(testEmail);
    await page.getByLabel(/^password$/i).fill('AnotherPassword123!');
    await page.getByLabel(/confirm password|repeat password/i).fill('AnotherPassword123!');

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

    // Verify error message
    await expect(
      page.getByText(/email already exists|already registered|duplicate|account exists/i).first()
    ).toBeVisible({ timeout: 5000 });

    // Should stay on register page
    await expect(page).toHaveURL(/\/register/);
  });

  test('should show error for password mismatch', async ({ page }) => {
    const testUser = generateTestUser('Mismatch');

    // Fill registration form with mismatched passwords
    await page.getByLabel(/full name|name/i).fill(testUser.fullName);
    await page.getByLabel(/email/i).fill(testUser.email);
    await page.getByLabel(/^password$/i).fill(testUser.password);
    await page.getByLabel(/confirm password|repeat password/i).fill('DifferentPassword123!');

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

    // Verify error message about password mismatch
    await expect(
      page.getByText(/password.*match|password.*mismatch|passwords.*not.*match/i).first()
    ).toBeVisible({ timeout: 5000 });

    // Should stay on register page
    await expect(page).toHaveURL(/\/register/);
  });

  test('should show error for invalid email format', async ({ page }) => {
    // Fill registration form with invalid email
    await page.getByLabel(/full name|name/i).fill('Test User');
    await page.getByLabel(/email/i).fill('invalid-email-format');
    await page.getByLabel(/^password$/i).fill('ValidPassword123!');
    await page.getByLabel(/confirm password|repeat password/i).fill('ValidPassword123!');

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

    // Verify error message about invalid email
    await expect(
      page.getByText(/valid email|invalid email|email format|email address/i).first()
    ).toBeVisible({ timeout: 5000 });

    // Should stay on register page
    await expect(page).toHaveURL(/\/register/);
  });

  test('should show error for weak password', async ({ page }) => {
    // Fill registration form with weak password
    await page.getByLabel(/full name|name/i).fill('Test User');
    await page.getByLabel(/email/i).fill(generateTestEmail());
    await page.getByLabel(/^password$/i).fill('123');
    await page.getByLabel(/confirm password|repeat password/i).fill('123');

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

    // Verify error message about weak password
    await expect(
      page.getByText(/password.*too short|weak password|password.*at least|password.*minimum/i).first()
    ).toBeVisible({ timeout: 5000 });
  });

  test('should validate required fields', async ({ page }) => {
    // Submit empty form
    await page.getByRole('button', { name: /register|sign up|create account/i }).click();

    // Verify validation errors for required fields
    await expect(
      page.getByText(/required|please fill|field is empty/i).first()
    ).toBeVisible({ timeout: 5000 });
  });

  test('should navigate to login page from register', async ({ page }) => {
    // Find and click login link
    const loginLink = page.getByRole('link', { name: /sign in|login|already have account/i });
    await loginLink.click();

    // Verify navigation to login page
    await expect(page).toHaveURL(/\/login/);
    await expect(page.getByRole('heading', { name: /login|sign in/i })).toBeVisible();
  });
});

// ============================================
// TEST SUITE: Login
// ============================================
test.describe('QA-AUTH-019: Login', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login');
    await page.waitForLoadState('networkidle');
  });

  test('should login with valid credentials', async ({ page, request }) => {
    // First register a user
    const testUser = generateTestUser('Login');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    // Clear and navigate to login
    await page.goto('/login');
    await page.waitForLoadState('networkidle');

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

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

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

    // Verify user is authenticated
    expect(await isAuthenticated(page)).toBe(true);
  });

  test('should show error for invalid credentials', async ({ page }) => {
    // Fill login form with invalid credentials
    await page.getByLabel(/email/i).fill('invalid@example.com');
    await page.getByLabel(/password/i).fill('wrongpassword123!');

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

    // Verify error message
    await expect(
      page.getByText(/invalid.*credential|incorrect.*password|wrong.*email|authentication.*failed/i).first()
    ).toBeVisible({ timeout: 5000 });

    // Should stay on login page
    await expect(page).toHaveURL(/\/login/);
  });

  test('should show error for non-existent user', async ({ page }) => {
    // Fill login form with non-existent email
    await page.getByLabel(/email/i).fill(generateTestEmail('nonexistent'));
    await page.getByLabel(/password/i).fill('SomePassword123!');

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

    // Verify error message
    await expect(
      page.getByText(/invalid.*credential|user.*not found|account.*not exist/i).first()
    ).toBeVisible({ timeout: 5000 });
  });

  test('should validate email format', async ({ page }) => {
    // Fill login form with invalid email format
    await page.getByLabel(/email/i).fill('not-an-email');
    await page.getByLabel(/password/i).fill('SomePassword123!');

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

    // Verify validation error
    await expect(
      page.getByText(/valid email|invalid email|email format/i).first()
    ).toBeVisible({ timeout: 5000 });
  });

  test('should navigate to register page from login', async ({ page }) => {
    // Find and click register link
    const registerLink = page.getByRole('link', { name: /sign up|register|create account/i });
    await registerLink.click();

    // Verify navigation to register page
    await expect(page).toHaveURL(/\/register/);
    await expect(page.getByRole('heading', { name: /register|sign up/i })).toBeVisible();
  });

  test('should navigate to forgot password page', async ({ page }) => {
    // Find and click forgot password link
    const forgotLink = page.getByRole('link', { name: /forgot.*password|reset.*password/i });
    
    if (await forgotLink.isVisible().catch(() => false)) {
      await forgotLink.click();

      // Verify navigation to forgot password page
      await expect(page).toHaveURL(/\/forgot-password|reset-password/);
    }
  });
});

// ============================================
// TEST SUITE: Protected Routes
// ============================================
test.describe('QA-AUTH-019: Protected Routes', () => {
  test('should redirect to login when accessing /scenarios without auth', async ({ page }) => {
    // Clear any existing auth
    await clearAuthToken(page);

    // Try to access protected route directly
    await page.goto('/scenarios');
    await page.waitForLoadState('networkidle');

    // Should redirect to login
    await waitForAuthRedirect(page, '/login');
    await expect(page.getByRole('heading', { name: /login|sign in/i })).toBeVisible();
  });

  test('should redirect to login when accessing /profile without auth', async ({ page }) => {
    await clearAuthToken(page);

    await page.goto('/profile');
    await page.waitForLoadState('networkidle');

    await waitForAuthRedirect(page, '/login');
  });

  test('should redirect to login when accessing /settings without auth', async ({ page }) => {
    await clearAuthToken(page);

    await page.goto('/settings');
    await page.waitForLoadState('networkidle');

    await waitForAuthRedirect(page, '/login');
  });

  test('should redirect to login when accessing /settings/api-keys without auth', async ({ page }) => {
    await clearAuthToken(page);

    await page.goto('/settings/api-keys');
    await page.waitForLoadState('networkidle');

    await waitForAuthRedirect(page, '/login');
  });

  test('should allow access to /scenarios with valid auth', async ({ page, request }) => {
    // Register and login a user
    const testUser = generateTestUser('Protected');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    // Login via UI
    await loginUserViaUI(page, testUser.email, testUser.password);

    // Now try to access protected route
    await page.goto('/scenarios');
    await page.waitForLoadState('networkidle');

    // Should stay on scenarios page
    await expect(page).toHaveURL('/scenarios');
    await expect(page.getByRole('heading', { name: 'Scenarios' })).toBeVisible();
  });

  test('should persist auth state after page refresh', async ({ page, request }) => {
    // Register and login
    const testUser = generateTestUser('Persist');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    await loginUserViaUI(page, testUser.email, testUser.password);

    // Refresh page
    await page.reload();
    await waitForLoading(page);

    // Should still be authenticated and on dashboard
    await expect(page).toHaveURL('/');
    await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
    expect(await isAuthenticated(page)).toBe(true);
  });
});

// ============================================
// TEST SUITE: Logout
// ============================================
test.describe('QA-AUTH-019: Logout', () => {
  test('should logout and redirect to login', async ({ page, request }) => {
    // Register and login
    const testUser = generateTestUser('Logout');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    await loginUserViaUI(page, testUser.email, testUser.password);

    // Verify logged in
    expect(await isAuthenticated(page)).toBe(true);

    // Logout
    await logoutUser(page);

    // Verify redirect to login
    await expect(page).toHaveURL('/login');
    await expect(page.getByRole('heading', { name: /login|sign in/i })).toBeVisible();
  });

  test('should clear tokens on logout', async ({ page, request }) => {
    // Register and login
    const testUser = generateTestUser('ClearTokens');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    await loginUserViaUI(page, testUser.email, testUser.password);

    // Logout
    await logoutUser(page);

    // Check local storage is cleared
    const accessToken = await page.evaluate(() => localStorage.getItem('access_token'));
    const refreshToken = await page.evaluate(() => localStorage.getItem('refresh_token'));

    expect(accessToken).toBeNull();
    expect(refreshToken).toBeNull();
  });

  test('should not access protected routes after logout', async ({ page, request }) => {
    // Register and login
    const testUser = generateTestUser('AfterLogout');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    await loginUserViaUI(page, testUser.email, testUser.password);
    await logoutUser(page);

    // Try to access protected route
    await page.goto('/scenarios');
    await page.waitForLoadState('networkidle');

    // Should redirect to login
    await waitForAuthRedirect(page, '/login');
  });
});

// ============================================
// TEST SUITE: Token Management
// ============================================
test.describe('QA-AUTH-019: Token Management', () => {
  test('should refresh token when expired', async ({ page, request }) => {
    // This test verifies the token refresh mechanism
    // Implementation depends on how the frontend handles token expiration
    test.skip(true, 'Token refresh testing requires controlled token expiration');
  });

  test('should store tokens in localStorage', async ({ page, request }) => {
    const testUser = generateTestUser('TokenStorage');
    const registerResponse = await request.post('http://localhost:8000/api/v1/auth/register', {
      data: {
        email: testUser.email,
        password: testUser.password,
        full_name: testUser.fullName,
      },
    });

    if (!registerResponse.ok()) {
      test.skip();
    }

    await loginUserViaUI(page, testUser.email, testUser.password);

    // Check tokens are stored
    const accessToken = await page.evaluate(() => localStorage.getItem('access_token'));
    const refreshToken = await page.evaluate(() => localStorage.getItem('refresh_token'));

    expect(accessToken).toBeTruthy();
    expect(refreshToken).toBeTruthy();
  });
});
