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

/**
 * Test utilities for Playwright E2E tests
 */

export class TestHelpers {
  constructor(private page: Page) {}

  /**
   * Navigate to a page with language prefix
   */
  async navigateToPage(path: string, lang: 'en' | 'ar' = 'en') {
    const fullPath = path.startsWith('/') ? path : `/${path}`;
    await this.page.goto(`/${lang}${fullPath}`);
  }

  /**
   * Wait for page to be fully loaded
   */
  async waitForPageLoad() {
    await this.page.waitForLoadState('networkidle');
    await this.page.waitForLoadState('domcontentloaded');
  }

  /**
   * Check if element is visible and in viewport
   */
  async isInViewport(selector: string): Promise<boolean> {
    const element = this.page.locator(selector);
    if (!(await element.isVisible())) {
      return false;
    }

    const box = await element.boundingBox();
    if (!box) return false;

    const viewport = this.page.viewportSize();
    if (!viewport) return false;

    return (
      box.y >= 0 &&
      box.x >= 0 &&
      box.y + box.height <= viewport.height &&
      box.x + box.width <= viewport.width
    );
  }

  /**
   * Fill form with data
   */
  async fillForm(formData: Record<string, string>) {
    for (const [name, value] of Object.entries(formData)) {
      const input = this.page.locator(`[name="${name}"], #${name}`);
      if (await input.isVisible()) {
        await input.fill(value);
      }
    }
  }

  /**
   * Check accessibility issues
   */
  async checkAccessibility() {
    // Check for images without alt text
    const imagesWithoutAlt = await this.page.locator('img:not([alt])').count();
    expect(imagesWithoutAlt).toBe(0);

    // Check for buttons without accessible names
    const buttons = await this.page.locator('button').all();
    for (const button of buttons) {
      const text = await button.textContent();
      const ariaLabel = await button.getAttribute('aria-label');
      expect(text || ariaLabel).toBeTruthy();
    }

    // Check heading hierarchy
    const h1Count = await this.page.locator('h1').count();
    expect(h1Count).toBe(1);
  }

  /**
   * Test responsive layout
   */
  async testResponsive() {
    const viewports = [
      { width: 375, height: 667, name: 'mobile' },
      { width: 768, height: 1024, name: 'tablet' },
      { width: 1920, height: 1080, name: 'desktop' },
    ];

    for (const viewport of viewports) {
      await this.page.setViewportSize(viewport);
      await this.waitForPageLoad();

      // Check that main content is visible
      await expect(this.page.locator('main, body')).toBeVisible();
    }
  }

  /**
   * Switch language
   */
  async switchLanguage(targetLang: 'en' | 'ar') {
    const langButton = this.page.locator(`text=${targetLang.toUpperCase()}`);
    await langButton.click();
    await this.waitForPageLoad();
    await expect(this.page).toHaveURL(new RegExp(`/${targetLang}`));
  }

  /**
   * Check for console errors
   */
  async checkConsoleErrors(): Promise<string[]> {
    const errors: string[] = [];

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

    return errors;
  }

  /**
   * Test navigation flow
   */
  async testNavigation(links: Array<{ text: string; expectedUrl: RegExp }>) {
    for (const link of links) {
      await this.page.getByRole('link', { name: link.text }).click();
      await expect(this.page).toHaveURL(link.expectedUrl);
      await this.page.goBack();
    }
  }

  /**
   * Test form validation
   */
  async testFormValidation(formSelector: string, requiredFields: string[]) {
    // Try to submit empty form
    await this.page.locator(`${formSelector} button[type="submit"]`).click();

    // Check for error messages
    for (const field of requiredFields) {
      const errorMessage = this.page.locator(`text=/required|${field}/i`);
      const count = await errorMessage.count();
      expect(count).toBeGreaterThanOrEqual(0);
    }
  }

  /**
   * Take screenshot with name
   */
  async takeScreenshot(name: string) {
    await this.page.screenshot({ path: `screenshots/${name}.png`, fullPage: true });
  }

  /**
   * Wait for animations to complete
   */
  async waitForAnimations() {
    await this.page.waitForTimeout(500);
  }

  /**
   * Check RTL layout
   */
  async checkRTLLayout() {
    const nav = this.page.locator('nav');
    await expect(nav).toHaveAttribute('dir', 'rtl');

    const body = this.page.locator('body');
    const direction = await body.evaluate((el) => window.getComputedStyle(el).direction);
    expect(direction).toBe('rtl');
  }

  /**
   * Check LTR layout
   */
  async checkLTRLayout() {
    const nav = this.page.locator('nav');
    await expect(nav).toHaveAttribute('dir', 'ltr');

    const body = this.page.locator('body');
    const direction = await body.evaluate((el) => window.getComputedStyle(el).direction);
    expect(direction).toBe('ltr');
  }

  /**
   * Test keyboard navigation
   */
  async testKeyboardNavigation() {
    // Tab through interactive elements
    for (let i = 0; i < 5; i++) {
      await this.page.keyboard.press('Tab');
      await this.page.waitForTimeout(100);
    }

    // Check that focus is on an interactive element
    const focusedElement = await this.page.evaluate(() => {
      const el = document.activeElement;
      return el?.tagName;
    });

    expect(['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']).toContain(focusedElement);
  }

  /**
   * Check performance metrics
   */
  async checkPerformance() {
    const metrics = await this.page.evaluate(() => {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      return {
        loadTime: navigation.loadEventEnd - navigation.fetchStart,
        domContentLoaded: navigation.domContentLoadedEventEnd - navigation.fetchStart,
        firstPaint: performance.getEntriesByType('paint')[0]?.startTime || 0,
      };
    });

    // Load time should be reasonable (< 5 seconds)
    expect(metrics.loadTime).toBeLessThan(5000);

    return metrics;
  }

  /**
   * Test mobile menu
   */
  async testMobileMenu() {
    await this.page.setViewportSize({ width: 375, height: 667 });

    const menuButton = this.page.getByRole('button', { name: /menu/i });
    await expect(menuButton).toBeVisible();

    await menuButton.click();

    // Menu should be open
    const mobileNav = this.page.locator('#mobile-nav, [role="navigation"]');
    await expect(mobileNav).toBeVisible();
  }
}

/**
 * Generate unique test data
 */
export function generateTestData() {
  const timestamp = Date.now();
  return {
    email: `test${timestamp}@example.com`,
    name: `Test User ${timestamp}`,
    phone: `+1234567${timestamp.toString().slice(-3)}`,
    company: `Test Company ${timestamp}`,
  };
}

/**
 * Wait for specific time
 */
export async function wait(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * Retry function with backoff
 */
export async function retry<T>(
  fn: () => Promise<T>,
  maxAttempts: number = 3,
  delay: number = 1000
): Promise<T> {
  let lastError: Error | undefined;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error as Error;
      if (attempt < maxAttempts) {
        await wait(delay * attempt);
      }
    }
  }

  throw lastError;
}
