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

export interface TestUser {
  email: string;
  password: string;
  name: string;
}

export interface NetworkLog {
  url: string;
  method: string;
  status: number;
  timing: number;
}

/**
 * The seed user credentials for E2E testing.
 * This user is pre-created in the production database via the seed script.
 * Uses environment variables with fallback to defaults for CI.
 */
export function getSeedUser(): TestUser {
  return {
    email: process.env.SEED_USER_EMAIL || 'e2e-test@localhost',
    password: process.env.SEED_USER_PASSWORD || 'TestPassword123!',
    name: process.env.SEED_USER_NAME || 'E2E Test User',
  };
}

/**
 * Login the seed user via the browser UI.
 * Returns after the dashboard has loaded.
 */
export async function loginSeedUser(page: Page): Promise<void> {
  const user = getSeedUser();
  await loginUser(page, user.email, user.password);
}

/**
 * Login a user via the browser UI.
 */
export async function loginUser(page: Page, email: string, password: string): Promise<void> {
  await page.goto('/auth/login');
  await page.fill('input[name="email"]', email);
  await page.fill('input[name="password"]', password);
  await page.click('button[type="submit"]');

  // Wait for navigation to dashboard
  await page.waitForURL('**/dashboard', { timeout: 15000 });
}

/**
 * Take a screenshot and save to e2e/screenshots/
 */
export async function takeScreenshot(page: Page, name: string): Promise<void> {
  await page.screenshot({
    path: `e2e/screenshots/${name}.png`,
    fullPage: true,
  });
}

/**
 * Track console errors on the page.
 * Returns an array that collects errors in real-time.
 */
export function setupConsoleErrorTracking(page: Page): string[] {
  const errors: string[] = [];

  page.on('console', (msg) => {
    if (msg.type() === 'error') {
      errors.push(msg.text());
    }
  });

  page.on('pageerror', (error) => {
    errors.push(error.message);
  });

  return errors;
}

/**
 * Track all console messages (not just errors) for verbose debugging.
 */
export function setupFullConsoleTracking(page: Page): { errors: string[]; warnings: string[]; logs: string[] } {
  const result = { errors: [] as string[], warnings: [] as string[], logs: [] as string[] };

  page.on('console', (msg) => {
    const text = msg.text();
    if (msg.type() === 'error') result.errors.push(text);
    else if (msg.type() === 'warning') result.warnings.push(text);
    else result.logs.push(text);
  });

  page.on('pageerror', (error) => {
    result.errors.push(error.message);
  });

  return result;
}

/**
 * Track network requests and responses, logging failed API calls.
 * Returns an object with logs array and helper to get failed requests.
 */
export function setupNetworkTracking(page: Page): { logs: NetworkLog[]; getFailedRequests: () => NetworkLog[] } {
  const logs: NetworkLog[] = [];
  const requestTimings = new Map<string, number>();

  page.on('request', (request) => {
    requestTimings.set(request.url(), Date.now());
  });

  page.on('response', (response: Response) => {
    const url = response.url();
    const startTime = requestTimings.get(url) || Date.now();
    logs.push({
      url,
      method: response.request().method(),
      status: response.status(),
      timing: Date.now() - startTime,
    });
  });

  return {
    logs,
    getFailedRequests: () => logs.filter((l) => l.status >= 400),
  };
}

/**
 * Assert zero console errors and zero failed API requests.
 * Filters out known benign errors (e.g., favicon 404, HMR websocket).
 */
export function assertCleanPage(
  consoleErrors: string[],
  networkLogs?: { getFailedRequests: () => NetworkLog[] },
): void {
  const ignoredConsolePatterns = [
    /favicon/i,
    /hydration/i,  // Next.js hydration mismatch warnings sometimes appear as errors
    /Failed to load resource/i, // Browser-generated 404 during auth redirects
  ];

  const realErrors = consoleErrors.filter(
    (err) => !ignoredConsolePatterns.some((pattern) => pattern.test(err)),
  );

  if (realErrors.length > 0) {
    throw new Error(`Console errors detected:\n${realErrors.join('\n')}`);
  }

  if (networkLogs) {
    const ignoredUrlPatterns = [/favicon\.ico/, /__nextjs/, /hot-update/];
    const failedRequests = networkLogs
      .getFailedRequests()
      .filter((r) => !ignoredUrlPatterns.some((p) => p.test(r.url)));

    if (failedRequests.length > 0) {
      const details = failedRequests
        .map((r) => `  ${r.method} ${r.url} -> ${r.status}`)
        .join('\n');
      throw new Error(`Failed network requests:\n${details}`);
    }
  }
}
