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

/**
 * General utility functions for Playwright tests
 */

/**
 * Waits for the loading spinner to disappear
 */
export async function waitForLoadingToFinish(page: Page) {
  // Adjust selectors based on your loading indicators
  await page.waitForSelector('[data-testid="loading"], .loading, .spinner', {
    state: 'hidden',
    timeout: 10000,
  }).catch(() => {
    // If no loading indicator found, that's fine
  });
}

/**
 * Waits for an API call to complete
 */
export async function waitForApiCall(page: Page, urlPattern: string | RegExp) {
  return page.waitForResponse(
    (response) => {
      const url = response.url();
      if (typeof urlPattern === 'string') {
        return url.includes(urlPattern);
      }
      return urlPattern.test(url);
    },
    { timeout: 15000 }
  );
}

/**
 * Mocks an API endpoint with a custom response
 */
export async function mockApiResponse(
  page: Page,
  urlPattern: string | RegExp,
  response: any,
  statusCode: number = 200
) {
  await page.route(urlPattern, async (route) => {
    await route.fulfill({
      status: statusCode,
      contentType: 'application/json',
      body: JSON.stringify(response),
    });
  });
}

/**
 * Checks if a toast/notification is visible
 */
export async function expectToastMessage(page: Page, message: string | RegExp) {
  // Adjust selector based on your toast implementation
  const toast = page.locator('[role="alert"], .toast, .notification');
  await expect(toast).toContainText(message, { timeout: 5000 });
}

/**
 * Fills a form field by label
 */
export async function fillFormField(page: Page, label: string | RegExp, value: string) {
  await page.getByLabel(label).fill(value);
}

/**
 * Selects an option from a dropdown by label
 */
export async function selectDropdownOption(page: Page, label: string | RegExp, value: string) {
  await page.getByLabel(label).selectOption(value);
}

/**
 * Uploads a file to a file input
 */
export async function uploadFile(page: Page, inputSelector: string, filePath: string) {
  const fileInput = page.locator(inputSelector);
  await fileInput.setInputFiles(filePath);
}

/**
 * Scrolls an element into view
 */
export async function scrollIntoView(page: Page, selector: string) {
  await page.locator(selector).scrollIntoViewIfNeeded();
}

/**
 * Takes a screenshot with a custom name
 */
export async function takeScreenshot(page: Page, name: string) {
  await page.screenshot({ path: `test-results/screenshots/${name}.png`, fullPage: true });
}

/**
 * Waits for navigation to complete
 */
export async function waitForNavigation(page: Page, urlPattern?: string | RegExp) {
  if (urlPattern) {
    await page.waitForURL(urlPattern);
  } else {
    await page.waitForLoadState('networkidle');
  }
}

/**
 * Generates a unique test identifier
 */
export function generateTestId(prefix: string = 'test'): string {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
}

/**
 * Waits for a specific amount of time (use sparingly, prefer waitFor* methods)
 */
export async function wait(ms: number) {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

/**
 * Retries an action until it succeeds or max attempts reached
 */
export async function retryAction<T>(
  action: () => Promise<T>,
  maxAttempts: number = 3,
  delayMs: number = 1000
): Promise<T> {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await action();
    } catch (error) {
      if (attempt === maxAttempts) {
        throw error;
      }
      await wait(delayMs);
    }
  }
  throw new Error('Retry action failed');
}

/**
 * Checks if an element is visible on the page
 */
export async function isVisible(page: Page, selector: string): Promise<boolean> {
  try {
    await page.locator(selector).waitFor({ state: 'visible', timeout: 2000 });
    return true;
  } catch {
    return false;
  }
}

/**
 * Accepts cookie consent dialog if present
 * Should be called after navigating to a page
 */
export async function acceptCookieConsent(page: Page) {
  try {
    const acceptButton = page.getByRole('button', {
      name: /aceptar todas|accept all/i,
    });

    const isVisible = await acceptButton.isVisible({ timeout: 2000 }).catch(() => false);

    if (isVisible) {
      await acceptButton.click();
      // Wait a bit for the dialog to close
      await page.waitForTimeout(500);
    }
  } catch (error) {
    // Cookie dialog not present, that's fine
  }
}
