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

export class TestHelpers {
  static async waitForElementVisible(locator: Locator, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'visible', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async waitForElementHidden(locator: Locator, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'hidden', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async safeClick(locator: Locator, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'visible', timeout });
      await locator.click();
      return true;
    } catch (error) {
      console.warn('Safe click failed:', error);
      return false;
    }
  }

  static async safeFill(locator: Locator, value: string, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'visible', timeout });
      await locator.clear();
      await locator.fill(value);
      return true;
    } catch (error) {
      console.warn('Safe fill failed:', error);
      return false;
    }
  }

  static async safeSelect(locator: Locator, value: string, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'visible', timeout });
      await locator.selectOption(value);
      return true;
    } catch (error) {
      console.warn('Safe select failed:', error);
      return false;
    }
  }

  static async retryOperation<T>(
    operation: () => Promise<T>,
    maxRetries: number = 3,
    delayMs: number = 1000
  ): Promise<T | null> {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        if (attempt === maxRetries) {
          console.error(`Operation failed after ${maxRetries} attempts:`, error);
          return null;
        }
        console.log(`Attempt ${attempt} failed, retrying in ${delayMs}ms...`);
        await new Promise(resolve => setTimeout(resolve, delayMs));
      }
    }
    return null;
  }

  static async waitForNetworkIdle(page: Page, timeout: number = 10000): Promise<void> {
    try {
      await page.waitForLoadState('networkidle', { timeout });
    } catch (error) {
      console.warn('Network idle timeout, continuing...');
    }
  }

  static async waitForNavigation(page: Page, urlPattern: RegExp, timeout: number = 10000): Promise<boolean> {
    try {
      await page.waitForURL(urlPattern, { timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async handleDialog(page: Page, action: 'accept' | 'dismiss' = 'accept'): Promise<void> {
    page.on('dialog', async dialog => {
      if (action === 'accept') {
        await dialog.accept();
      } else {
        await dialog.dismiss();
      }
    });
  }

  static async getTableData(table: Locator): Promise<string[][]> {
    const rows = await table.locator('tbody tr').all();
    const data: string[][] = [];

    for (const row of rows) {
      const cells = await row.locator('td').allTextContents();
      data.push(cells);
    }

    return data;
  }

  static async findTableRowByContent(table: Locator, content: string): Promise<Locator | null> {
    const rows = await table.locator('tbody tr').all();
    
    for (const row of rows) {
      const textContent = await row.textContent();
      if (textContent && textContent.includes(content)) {
        return row;
      }
    }
    
    return null;
  }

  static async scrollToElement(page: Page, locator: Locator): Promise<void> {
    await locator.scrollIntoViewIfNeeded();
    await page.waitForTimeout(300);
  }

  static async waitForAnimation(locator: Locator): Promise<void> {
    await locator.waitFor({ state: 'attached' });
    await locator.evaluate(el => {
      return new Promise(resolve => {
        requestAnimationFrame(() => {
          setTimeout(resolve, 300);
        });
      });
    });
  }

  static async takeScreenshot(page: Page, name: string): Promise<void> {
    await page.screenshot({ path: `test-results/screenshots/${name}.png`, fullPage: true });
  }

  static async waitForPageLoad(page: Page, timeout: number = 10000): Promise<void> {
    try {
      await page.waitForLoadState('load', { timeout });
    } catch (error) {
      console.warn('Page load timeout, continuing...');
    }
  }

  static async waitForDOMContent(page: Page, timeout: number = 10000): Promise<void> {
    try {
      await page.waitForLoadState('domcontentloaded', { timeout });
    } catch (error) {
      console.warn('DOM content load timeout, continuing...');
    }
  }

  static async isElementVisible(locator: Locator): Promise<boolean> {
    try {
      return await locator.isVisible({ timeout: 1000 });
    } catch {
      return false;
    }
  }

  static async isElementEnabled(locator: Locator): Promise<boolean> {
    try {
      return await locator.isEnabled({ timeout: 1000 });
    } catch {
      return false;
    }
  }

  static async getElementText(locator: Locator): Promise<string | null> {
    try {
      return await locator.textContent({ timeout: 5000 });
    } catch {
      return null;
    }
  }

  static async getElementCount(locator: Locator): Promise<number> {
    try {
      return await locator.count();
    } catch {
      return 0;
    }
  }

  static async waitForTextContent(locator: Locator, expectedText: string, timeout: number = 5000): Promise<boolean> {
    try {
      await locator.waitFor({ state: 'visible', timeout });
      const text = await locator.textContent();
      return text !== null && text.includes(expectedText);
    } catch {
      return false;
    }
  }

  static async clearInput(locator: Locator): Promise<void> {
    await locator.click();
    await locator.fill('');
    await locator.press('Control+A');
    await locator.press('Backspace');
  }

  static async waitForSuccessMessage(page: Page, timeout: number = 5000): Promise<boolean> {
    const successMessage = page.locator('.el-message--success, .success-message, [class*="success"]');
    try {
      await successMessage.waitFor({ state: 'visible', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async waitForErrorMessage(page: Page, timeout: number = 5000): Promise<boolean> {
    const errorMessage = page.locator('.el-message--error, .error-message, [class*="error"]');
    try {
      await errorMessage.waitFor({ state: 'visible', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async waitForLoadingComplete(page: Page, timeout: number = 10000): Promise<void> {
    const loadingSpinner = page.locator('.el-loading-mask, .loading, [class*="loading"]');
    
    try {
      await loadingSpinner.waitFor({ state: 'visible', timeout: 2000 });
      await loadingSpinner.waitFor({ state: 'hidden', timeout });
    } catch {
      console.log('No loading spinner found or already hidden');
    }
  }

  static async waitForModal(page: Page, timeout: number = 5000): Promise<boolean> {
    const modal = page.locator('.el-dialog, .modal, [role="dialog"]');
    try {
      await modal.waitFor({ state: 'visible', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async closeModal(page: Page): Promise<boolean> {
    const closeButton = page.locator('.el-dialog__close, .modal-close, button[aria-label="Close"]');
    try {
      await closeButton.click();
      return true;
    } catch {
      return false;
    }
  }

  static async waitForSelectDropdown(page: Page, timeout: number = 5000): Promise<boolean> {
    const dropdown = page.locator('.el-select-dropdown, .select-dropdown');
    try {
      await dropdown.waitFor({ state: 'visible', timeout });
      return true;
    } catch {
      return false;
    }
  }

  static async selectFromDropdown(page: Page, value: string): Promise<boolean> {
    const option = page.locator('.el-select-dropdown__item, .select-option').filter({ hasText: value });
    try {
      await option.click();
      return true;
    } catch {
      return false;
    }
  }
}