/**
 * E2E Tests for Google OAuth Flows
 *
 * These tests verify that:
 * 1. Google OAuth buttons are present and clickable
 * 2. Clicking "Sign up with Google" redirects to Google OAuth
 * 3. Clicking "Sign in with Google" redirects to Google OAuth
 * 4. No MissingCSRF errors occur when initiating OAuth
 *
 * Note: These tests verify the OAuth flow INITIATES correctly.
 * Full OAuth flow testing requires mocking Google's OAuth server
 * or using a real test account, which is outside E2E scope.
 */

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

// =============================================================================
// Test Configuration
// =============================================================================

/** Centralized configuration for easy updates */
const CONFIG = {
  /** Test timeouts in milliseconds */
  timeouts: {
    test: 60000,
    pageLoad: 2000,
    navigation: 15000,
    postClick: 3000,
    elementVisible: 10000,
  },

  /** API endpoints for NextAuth */
  endpoints: {
    base: 'http://localhost:9000',
    providers: 'http://localhost:9000/api/auth/providers',
    csrf: 'http://localhost:9000/api/auth/csrf',
    session: 'http://localhost:9000/api/auth/session',
    callbackError: '/api/auth/callback/google?error=access_denied',
  },

  /** Page routes */
  routes: {
    login: '/en/login',
  },

  /** Element selectors */
  selectors: {
    googleButton: 'button:has-text("Google"), button:has-text("google"), [data-testid="google-login"]',
  },

  /** Expected error strings that should NOT appear */
  errorPatterns: {
    missingCSRF: 'error=MissingCSRF',
    configuration: 'error=Configuration',
    prismaInit: 'PrismaClientInitializationError',
  },

  /** Valid URL patterns for successful OAuth initiation */
  validOAuthLocations: [
    'accounts.google.com',
    '/api/auth/',
    '/login',
  ],
} as const;

// Increase timeout for these tests since OAuth redirects can take time
test.setTimeout(CONFIG.timeouts.test);

// =============================================================================
// Helper Functions
// =============================================================================

/**
 * Navigate to login page and wait for it to load
 */
async function navigateToLoginPage(page: Page): Promise<void> {
  await page.goto(CONFIG.routes.login);
  await page.waitForLoadState('domcontentloaded');
  await page.waitForTimeout(CONFIG.timeouts.pageLoad);
}

/**
 * Get the Google OAuth button locator
 */
function getGoogleButton(page: Page) {
  return page.locator(CONFIG.selectors.googleButton);
}

/**
 * Click Google button and wait for navigation/redirect
 */
async function clickGoogleButtonAndWait(page: Page): Promise<string> {
  const googleButton = getGoogleButton(page).first();

  const navigationPromise = page.waitForNavigation({
    timeout: CONFIG.timeouts.navigation
  });

  await googleButton.click();

  try {
    await navigationPromise;
  } catch {
    // Navigation might not complete due to cross-origin redirect
  }

  await page.waitForTimeout(CONFIG.timeouts.postClick);
  return page.url();
}

/**
 * Assert URL does not contain any known error patterns
 */
function assertNoOAuthErrors(url: string): void {
  expect(url).not.toContain(CONFIG.errorPatterns.missingCSRF);
  expect(url).not.toContain(CONFIG.errorPatterns.configuration);
}

/**
 * Assert URL is at a valid OAuth location
 */
function assertValidOAuthLocation(url: string): void {
  const isValidLocation = CONFIG.validOAuthLocations.some(
    pattern => url.includes(pattern)
  );
  expect(isValidLocation).toBe(true);
}

/**
 * Verify Google provider exists in providers response
 */
function assertGoogleProviderConfigured(providers: Record<string, unknown>): void {
  expect(providers).toHaveProperty('google');
  const google = providers.google as Record<string, unknown>;
  expect(google).toHaveProperty('id', 'google');
  expect(google).toHaveProperty('name', 'Google');
}

// =============================================================================
// Test Suites
// =============================================================================

test.describe('Google OAuth Login Flow', () => {
  test.beforeEach(async ({ page }) => {
    await navigateToLoginPage(page);
  });

  test('should display Google OAuth button on login page', async ({ page }) => {
    const googleButton = getGoogleButton(page);
    await expect(googleButton.first()).toBeVisible({
      timeout: CONFIG.timeouts.elementVisible
    });
  });

  test('should initiate Google OAuth flow without CSRF error', async ({ page }) => {
    const currentUrl = await clickGoogleButtonAndWait(page);
    assertNoOAuthErrors(currentUrl);
  });

  test('should redirect towards Google OAuth', async ({ page }) => {
    const currentUrl = await clickGoogleButtonAndWait(page);
    assertNoOAuthErrors(currentUrl);
    assertValidOAuthLocation(currentUrl);
  });
});

test.describe('NextAuth API Routes', () => {
  test('should have providers endpoint available', async ({ request }) => {
    const response = await request.get(CONFIG.endpoints.providers);
    expect(response.status()).toBe(200);

    const providers = await response.json();
    assertGoogleProviderConfigured(providers);
  });

  test('should have CSRF token endpoint available', async ({ request }) => {
    const response = await request.get(CONFIG.endpoints.csrf);
    expect(response.status()).toBe(200);

    const csrf = await response.json();
    expect(csrf).toHaveProperty('csrfToken');
    expect(csrf.csrfToken).toBeTruthy();
  });

  test('should have session endpoint available', async ({ request }) => {
    const response = await request.get(CONFIG.endpoints.session);
    expect(response.status()).toBe(200);

    const session = await response.json();
    expect(typeof session).toBe('object');
  });
});

test.describe('OAuth Error Handling', () => {
  test('should handle invalid OAuth callback gracefully', async ({ page }) => {
    await page.goto(CONFIG.endpoints.callbackError);
    await page.waitForTimeout(CONFIG.timeouts.postClick);

    const pageContent = await page.content();
    expect(pageContent).not.toContain(CONFIG.errorPatterns.prismaInit);
  });
});

test.describe('CSRF Token Validation', () => {
  test('should return valid CSRF token format', async ({ request }) => {
    const response = await request.get(CONFIG.endpoints.csrf);
    expect(response.status()).toBe(200);

    const data = await response.json();
    expect(data.csrfToken).toBeDefined();
    expect(typeof data.csrfToken).toBe('string');
    expect(data.csrfToken.length).toBeGreaterThan(10);
  });

  test('should include Google in available providers', async ({ request }) => {
    const response = await request.get(CONFIG.endpoints.providers);
    expect(response.status()).toBe(200);

    const providers = await response.json();
    expect(providers.google).toBeDefined();
    expect(providers.google.type).toBe('oidc');
    expect(providers.google.signinUrl).toContain('/api/auth/signin/google');
  });
});
