/**
 * E2E Test Utilities
 * 
 * Shared utilities and helpers for E2E tests
 */

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

// Base URL for API calls
const API_BASE_URL = process.env.VITE_API_URL || 'http://localhost:8000/api/v1';

/**
 * Navigate to a page and wait for it to be ready
 */
export async function navigateTo(page: Page, path: string) {
  await page.goto(path);
  await page.waitForLoadState('networkidle');
}

/**
 * Wait for loading states to complete
 */
export async function waitForLoading(page: Page) {
  // Wait for any loading text to disappear
  const loadingElement = page.getByText('Loading...');
  await expect(loadingElement).toHaveCount(0, { timeout: 30000 });
}

/**
 * Wait for table to be populated
 */
export async function waitForTableData(page: Page, tableTestId?: string) {
  const tableSelector = tableTestId 
    ? `[data-testid="${tableTestId}"] tbody tr` 
    : 'table tbody tr';
  
  // Wait for at least one row to be present
  await page.waitForSelector(tableSelector, { timeout: 10000 });
}

/**
 * Create a scenario via API
 */
export async function createScenarioViaAPI(
  request: APIRequestContext,
  scenario: {
    name: string;
    description?: string;
    tags?: string[];
    region: string;
  },
  accessToken?: string
) {
  const headers: Record<string, string> = {};
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  }

  const response = await request.post(`${API_BASE_URL}/scenarios`, {
    data: scenario,
    headers: Object.keys(headers).length > 0 ? headers : undefined,
  });

  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Delete a scenario via API
 */
export async function deleteScenarioViaAPI(
  request: APIRequestContext,
  scenarioId: string,
  accessToken?: string
) {
  const headers: Record<string, string> = {};
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  }

  const response = await request.delete(`${API_BASE_URL}/scenarios/${scenarioId}`, {
    headers: Object.keys(headers).length > 0 ? headers : undefined,
  });
  
  // Accept 204 (No Content) or 200 (OK) or 404 (already deleted)
  expect([200, 204, 404]).toContain(response.status());
}

/**
 * Start a scenario via API
 */
export async function startScenarioViaAPI(
  request: APIRequestContext,
  scenarioId: string,
  accessToken?: string
) {
  const headers: Record<string, string> = {};
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  }

  const response = await request.post(`${API_BASE_URL}/scenarios/${scenarioId}/start`, {
    headers: Object.keys(headers).length > 0 ? headers : undefined,
  });
  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Stop a scenario via API
 */
export async function stopScenarioViaAPI(
  request: APIRequestContext,
  scenarioId: string,
  accessToken?: string
) {
  const headers: Record<string, string> = {};
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  }

  const response = await request.post(`${API_BASE_URL}/scenarios/${scenarioId}/stop`, {
    headers: Object.keys(headers).length > 0 ? headers : undefined,
  });
  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Send test logs to a scenario
 */
export async function sendTestLogs(
  request: APIRequestContext,
  scenarioId: string,
  logs: unknown[],
  accessToken?: string
) {
  const headers: Record<string, string> = {};
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  }

  const response = await request.post(
    `${API_BASE_URL}/scenarios/${scenarioId}/ingest`,
    {
      data: { logs },
      headers: Object.keys(headers).length > 0 ? headers : undefined,
    }
  );
  expect(response.ok()).toBeTruthy();
  return await response.json();
}

/**
 * Generate a unique test scenario name
 */
export function generateTestScenarioName(prefix = 'E2E Test'): string {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  return `${prefix} ${timestamp}`;
}

/**
 * Wait for toast notification
 */
export async function waitForToast(page: Page, message?: string) {
  const toastSelector = '[data-testid="toast"]'
    + (message ? `:has-text("${message}")` : '');
  
  await page.waitForSelector(toastSelector, { timeout: 10000 });
}

/**
 * Click on a navigation link by label
 */
export async function clickNavigation(page: Page, label: string) {
  const navLink = page.locator('nav').getByRole('link', { name: label });
  await navLink.click();
  await page.waitForLoadState('networkidle');
}

/**
 * Get scenario by name from the scenarios table
 */
export async function getScenarioRow(page: Page, scenarioName: string) {
  return page.locator('table tbody tr').filter({ hasText: scenarioName });
}

/**
 * Open scenario actions dropdown
 */
export async function openScenarioActions(page: Page, scenarioName: string) {
  const row = await getScenarioRow(page, scenarioName);
  const actionsButton = row.locator('button').first();
  await actionsButton.click();
  return row.locator('[role="menu"]');
}

/**
 * Take a screenshot with a descriptive name
 */
export async function takeScreenshot(page: Page, name: string) {
  await page.screenshot({
    path: `e2e/screenshots/${name}.png`,
    fullPage: true,
  });
}

/**
 * Check if element is visible with retry
 */
export async function isElementVisible(
  page: Page,
  selector: string,
  timeout = 5000
): Promise<boolean> {
  try {
    await page.waitForSelector(selector, { timeout, state: 'visible' });
    return true;
  } catch {
    return false;
  }
}

/**
 * Mobile viewport helper
 */
export async function setMobileViewport(page: Page) {
  await page.setViewportSize({ width: 375, height: 667 });
}

/**
 * Tablet viewport helper
 */
export async function setTabletViewport(page: Page) {
  await page.setViewportSize({ width: 768, height: 1024 });
}

/**
 * Desktop viewport helper
 */
export async function setDesktopViewport(page: Page) {
  await page.setViewportSize({ width: 1280, height: 720 });
}
