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

export class TestStabilityHelper {
  private readonly page: Page;
  private readonly maxRetries: number = 3;
  private readonly retryDelay: number = 1000;

  constructor(page: Page) {
    this.page = page;
  }

  async waitForNetworkIdle(timeout: number = 30000): Promise<void> {
    try {
      await this.page.waitForLoadState('networkidle', { timeout });
    } catch (error) {
      console.log('Network idle timeout, continuing anyway');
    }
  }

  async waitForElementVisible(selector: string, timeout: number = 10000): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await expect(element).toBeVisible({ timeout });
    });
  }

  async safeClick(selector: string): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await element.waitFor({ state: 'visible', timeout: 10000 });
      await element.click({ timeout: 5000 });
    });
  }

  async safeFill(selector: string, value: string): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await element.waitFor({ state: 'visible', timeout: 10000 });
      await element.clear();
      await element.fill(value);
    });
  }

  async safeSelect(selector: string, value: string): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await element.waitFor({ state: 'visible', timeout: 10000 });
      await element.selectOption(value);
    });
  }

  async waitForURL(urlPattern: RegExp | string, timeout: number = 30000): Promise<void> {
    await this.retry(async () => {
      await this.page.waitForURL(urlPattern, { timeout });
    });
  }

  async handleModal(): Promise<void> {
    try {
      const modal = this.page.locator('.el-dialog, .el-message-box');
      const isVisible = await modal.isVisible({ timeout: 2000 });
      
      if (isVisible) {
        const confirmButton = modal.locator('.el-button--primary').first();
        const cancelButton = modal.locator('.el-button--default').first();
        
        if (await confirmButton.isVisible({ timeout: 1000 })) {
          await confirmButton.click();
        } else if (await cancelButton.isVisible({ timeout: 1000 })) {
          await cancelButton.click();
        }
      }
    } catch (error) {
      console.log('No modal found or modal handling failed');
    }
  }

  async waitForLoadingComplete(): Promise<void> {
    try {
      const loading = this.page.locator('.el-loading-mask, .loading');
      await loading.waitFor({ state: 'hidden', timeout: 10000 });
    } catch (error) {
      console.log('Loading element not found or timeout');
    }
  }

  async safeNavigate(url: string): Promise<void> {
    await this.retry(async () => {
      await this.page.goto(url, { waitUntil: 'networkidle', timeout: 30000 });
    });
  }

  async waitForTableData(tableSelector: string, minRows: number = 1): Promise<void> {
    await this.retry(async () => {
      const table = this.page.locator(tableSelector);
      await expect(table).toBeVisible({ timeout: 10000 });
      
      const rows = table.locator('.el-table__row');
      const rowCount = await rows.count();
      expect(rowCount).toBeGreaterThanOrEqual(minRows);
    });
  }

  async safeScrollIntoView(selector: string): Promise<void> {
    const element = this.page.locator(selector);
    await element.scrollIntoViewIfNeeded();
    await this.page.waitForTimeout(500);
  }

  async clearLocalStorage(): Promise<void> {
    await this.page.evaluate(() => {
      localStorage.clear();
    });
  }

  async clearSessionStorage(): Promise<void> {
    await this.page.evaluate(() => {
      sessionStorage.clear();
    });
  }

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

  async getErrorMessage(): Promise<string | null> {
    try {
      const errorElement = this.page.locator('.el-message--error, .error-message');
      const isVisible = await errorElement.isVisible({ timeout: 2000 });
      
      if (isVisible) {
        return await errorElement.textContent();
      }
      return null;
    } catch (error) {
      return null;
    }
  }

  async hasErrorMessage(): Promise<boolean> {
    const errorMessage = await this.getErrorMessage();
    return errorMessage !== null;
  }

  private async retry<T>(fn: () => Promise<T>): Promise<T> {
    let lastError: Error | undefined;
    
    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        return await fn();
      } catch (error) {
        lastError = error as Error;
        console.log(`Attempt ${attempt} failed, retrying...`, error);
        
        if (attempt < this.maxRetries) {
          await this.page.waitForTimeout(this.retryDelay);
        }
      }
    }
    
    throw lastError || new Error('All retry attempts failed');
  }

  async waitForElementNotVisible(selector: string, timeout: number = 10000): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await expect(element).not.toBeVisible({ timeout });
    });
  }

  async safeHover(selector: string): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await element.waitFor({ state: 'visible', timeout: 10000 });
      await element.hover({ timeout: 5000 });
    });
  }

  async waitForText(selector: string, text: string, timeout: number = 10000): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await expect(element).toContainText(text, { timeout });
    });
  }

  async waitForTextNotPresent(selector: string, text: string, timeout: number = 10000): Promise<void> {
    await this.retry(async () => {
      const element = this.page.locator(selector);
      await expect(element).not.toContainText(text, { timeout });
    });
  }
}