import { mkdir, rm } from 'node:fs/promises';
import { chromium } from 'playwright';

export const CLOSE_TIMEOUT_MS = 3000;
export const LAUNCH_TIMEOUT_MS = 10000;
export const CONTEXT_TIMEOUT_MS = 8000;
export const PAGE_TIMEOUT_MS = 15000;

// Chromium puts profiles and internal files in the process temp directory.
// Some CI/dev containers mount /tmp as a very small tmpfs, so the checks point
// it at an already-ignored directory under .astro/ instead.
export async function setupBrowserTmp(browserTmp) {
  await rm(browserTmp, { recursive: true, force: true });
  await mkdir(browserTmp, { recursive: true });
  process.env.TMPDIR = browserTmp;
  process.env.TMP = browserTmp;
  process.env.TEMP = browserTmp;
}

export async function cleanupBrowserTmp(browserTmp) {
  await rm(browserTmp, { recursive: true, force: true }).catch(() => {});
}

export async function withTimeout(promise, timeoutMs, label) {
  let timeout;
  try {
    return await Promise.race([
      promise,
      new Promise((_, reject) => {
        timeout = setTimeout(() => reject(new Error(label)), timeoutMs);
      }),
    ]);
  } finally {
    clearTimeout(timeout);
  }
}

export async function safeClosePage(page) {
  await withTimeout(
    page.close(),
    CLOSE_TIMEOUT_MS,
    'Timed out while closing Playwright page'
  ).catch(() => {});
}

export async function safeCloseContext(context) {
  await withTimeout(
    context.close(),
    CLOSE_TIMEOUT_MS,
    'Timed out while closing Playwright context'
  ).catch(() => {});
}

export async function safeCloseBrowser(browser) {
  const childProcess = browser.process?.();
  try {
    await withTimeout(
      browser.close(),
      CLOSE_TIMEOUT_MS,
      'Timed out while closing Chromium'
    );
  } catch {
    childProcess?.kill('SIGKILL');
  }
}

export function openBrowser(browserTmp) {
  return withTimeout(
    chromium.launch({
      headless: true,
      env: {
        ...process.env,
        TMPDIR: browserTmp,
        TMP: browserTmp,
        TEMP: browserTmp,
      },
      args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'],
    }),
    LAUNCH_TIMEOUT_MS,
    'Timed out while launching Chromium'
  );
}

export function shouldRetryNavigation(error) {
  const message = error instanceof Error ? error.message : String(error);
  return /ERR_INSUFFICIENT_RESOURCES|Execution context was destroyed|Target.*closed|has been closed|Timed out while|navigation/i.test(
    message
  );
}
