import { Page, expect } from '@playwright/test';
import { TEST_FILES } from './test-data';

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

  async waitForApiCall(urlPattern: string | RegExp, timeout = 10000) {
    return this.page.waitForResponse(resp => 
      typeof urlPattern === 'string' 
        ? resp.url().includes(urlPattern)
        : urlPattern.test(resp.url()), 
      { timeout }
    );
  }

  async uploadFile(inputSelector: string, filePath: string) {
    const fileInput = this.page.locator(inputSelector);
    await fileInput.setInputFiles(filePath);
  }

  async clearAndType(selector: string, text: string) {
    await this.page.fill(selector, '');
    await this.page.type(selector, text);
  }

  async waitForToast(message?: string) {
    const toast = this.page.locator('[data-testid="toast"], .toast, [role="alert"]');
    await expect(toast).toBeVisible({ timeout: 5000 });
    
    if (message) {
      await expect(toast).toContainText(message);
    }
    
    return toast;
  }

  async waitForLoadingToComplete() {
    // Wait for any loading spinners to disappear
    await this.page.waitForFunction(() => 
      !document.querySelector('[data-testid="loading"], .loading, [aria-label*="loading" i]')
    );
  }

  async waitForWebKitStability() {
    const browserName = await this.page.evaluate(() => navigator.userAgent);
    const isWebKit = browserName.includes('WebKit') && !browserName.includes('Chrome');
    
    if (isWebKit) {
      console.log('WebKit stability waiting initiated...');
      
      // Wait for network to be completely idle
      await this.page.waitForLoadState('networkidle');
      await this.page.waitForTimeout(3000);
      
      // Wait for JavaScript to finish executing
      await this.page.waitForFunction(() => {
        return document.readyState === 'complete' && 
               typeof window !== 'undefined';
      }, { timeout: 15000 });
      
      // Extra stability wait
      await this.page.waitForTimeout(2000);
      console.log('WebKit stability waiting completed');
    }
  }

  async waitForBrowserStability() {
    const browserName = await this.page.context().browser()?.browserType().name() || '';
    
    switch (browserName) {
      case 'webkit':
        await this.waitForWebKitStability();
        break;
      case 'firefox':
        // Firefox-specific stability wait
        console.log('Firefox stability waiting initiated...');
        await this.page.waitForLoadState('networkidle');
        await this.page.waitForTimeout(2000);
        // Firefox sometimes needs extra time for form validation
        await this.page.waitForFunction(() => {
          return document.readyState === 'complete' && 
                 typeof window !== 'undefined' &&
                 !document.querySelector('.MuiCircularProgress-root');
        }, { timeout: 15000 });
        console.log('Firefox stability waiting completed');
        break;
      default:
        // Chromium and others
        await this.page.waitForLoadState('networkidle');
        await this.page.waitForTimeout(500);
        break;
    }
  }

  async navigateToPage(path: string) {
    await this.page.goto(path);
    await this.waitForLoadingToComplete();
    
    // WebKit-specific stability waiting
    const browserName = await this.page.evaluate(() => navigator.userAgent);
    const isWebKit = browserName.includes('WebKit') && !browserName.includes('Chrome');
    
    if (isWebKit) {
      console.log('WebKit detected - adding stability waiting for page:', path);
      
      // Wait for network to be completely idle
      await this.page.waitForLoadState('networkidle');
      await this.page.waitForTimeout(3000);
      
      // Wait for JavaScript to finish executing and ensure we're not stuck on login
      await this.page.waitForFunction(() => {
        return document.readyState === 'complete' && 
               typeof window !== 'undefined' && 
               !window.location.href.includes('/login') &&
               !window.location.pathname.includes('/login');
      }, { timeout: 20000 });
      
      // Extra stability wait
      await this.page.waitForTimeout(2000);
      console.log('WebKit stability waiting completed for:', path);
    }
  }

  async takeScreenshotOnFailure(testName: string) {
    await this.page.screenshot({ 
      path: `test-results/screenshots/${testName}-${Date.now()}.png`,
      fullPage: true 
    });
  }

  async uploadTestDocument(fileName: string = 'test1.png') {
    try {
      console.log(`Uploading test document: ${fileName}`);
      
      // Navigate to upload page
      await this.page.goto('/upload');
      await this.waitForLoadingToComplete();
      
      // Look for file input - react-dropzone creates hidden inputs
      const fileInput = this.page.locator('input[type="file"]').first();
      await expect(fileInput).toBeAttached({ timeout: 10000 });
      
      // Upload the test file using the proper path from TEST_FILES
      const filePath = fileName === 'test1.png' ? TEST_FILES.test1 : `../tests/test_images/${fileName}`;
      await fileInput.setInputFiles(filePath);
      
      // Verify file is added to the list by looking for the filename
      await expect(this.page.getByText(fileName)).toBeVisible({ timeout: 5000 });
      
      // Look for the "Upload All" button which appears after files are selected
      const uploadButton = this.page.locator('button:has-text("Upload All"), button:has-text("Upload")');
      if (await uploadButton.isVisible({ timeout: 5000 })) {
        // Wait for upload API call
        const uploadPromise = this.waitForApiCall('/api/documents', 30000);
        
        await uploadButton.click();
        
        // Wait for upload to complete
        await uploadPromise;
        console.log('Upload completed successfully');
      } else {
        console.log('Upload button not found, file may have been uploaded automatically');
      }
      
      // Return to documents page
      await this.page.goto('/documents');
      await this.waitForLoadingToComplete();
      
      console.log('Returned to documents page after upload');
    } catch (error) {
      console.error('Error uploading test document:', error);
      // Return to documents page even if upload failed
      await this.page.goto('/documents');
      await this.waitForLoadingToComplete();
    }
  }

  async ensureTestDocumentsExist() {
    try {
      // Give the page time to load before checking for documents
      await this.waitForLoadingToComplete();
      
      // Check if there are any documents - use multiple selectors to be safe
      const documentSelectors = [
        '[data-testid="document-item"]',
        '.document-item', 
        '.document-card',
        '.MuiCard-root', // Material-UI cards commonly used for documents
        '[role="article"]' // Semantic role for document items
      ];
      
      let documentCount = 0;
      for (const selector of documentSelectors) {
        const count = await this.page.locator(selector).count();
        if (count > 0) {
          documentCount = count;
          break;
        }
      }
      
      console.log(`Found ${documentCount} documents on the page`);
      
      if (documentCount === 0) {
        console.log('No documents found, attempting to upload a test document...');
        // Upload a test document
        await this.uploadTestDocument('test1.png');
      }
    } catch (error) {
      console.log('Error checking for test documents:', error);
      // Don't fail the test if document check fails, just log it
    }
  }
}