const { test, expect } = require('playwright/test');
const { BASE_URL, trackErrors } = require('./helpers');

const LOAD_TIMEOUT = 30000;

async function loadExplorer(page, path) {
  await page.goto(BASE_URL + '/sx/' + path, {
    waitUntil: 'domcontentloaded',
    timeout: LOAD_TIMEOUT,
  });
  await page.waitForSelector('h1, .sx-render-error, [data-sx-boundary]', {
    timeout: LOAD_TIMEOUT,
  });
}

test.describe('Spec Explorer', () => {
  test('overview loads with evaluator definitions', async ({ page }) => {
    await loadExplorer(page, '(language.(spec.(explore.evaluator)))');

    await expect(page.locator('h1')).toHaveText('Evaluator');
    await expect(page.locator('text=/\\d+ defines/')).toBeVisible();
    await expect(page.locator('text=/\\d+ lines/')).toBeVisible();
    await expect(page.locator('h2:has-text("Definitions")')).toBeVisible();
    await expect(page.locator('#fn-make-cek-state')).toBeVisible();
    await expect(page.locator('#fn-cek-step')).toBeVisible();
    // eval-expr has 2 entries (forward decl + real), just check at least 1
    await expect(page.locator('#fn-eval-expr').first()).toBeVisible();
    await expect(page.locator('.sx-render-error')).toHaveCount(0);
  });

  test('no errors on initial load', async ({ page }) => {
    const tracker = trackErrors(page);
    await loadExplorer(page, '(language.(spec.(explore.evaluator)))');
    await expect(page.locator('h1')).toHaveText('Evaluator');
    expect(tracker.errors()).toEqual([]);
  });

  test('SPA nav to explorer has no render error', async ({ page }) => {
    await page.goto(BASE_URL + '/sx/(language.(spec))', {
      waitUntil: 'domcontentloaded',
      timeout: LOAD_TIMEOUT,
    });
    await page.waitForSelector('h1, h2', { timeout: LOAD_TIMEOUT });

    const link = page.locator('a[href*="explore.evaluator"]');
    if (await link.count() > 0) {
      await link.click();
      await page.waitForSelector('#fn-cek-step', { timeout: LOAD_TIMEOUT });
      await expect(page.locator('h1')).toHaveText('Evaluator');

      const content = await page.locator('#sx-content').textContent();
      expect(content).not.toContain('Render error');
      expect(content).not.toContain('Not callable');
    }
  });

  test('drill-in shows definition detail', async ({ page }) => {
    await loadExplorer(page, '(language.(spec.(explore.evaluator.cek-step)))');

    await expect(page.locator('text=cek-step').first()).toBeVisible();
    await expect(page.locator('text=function').first()).toBeVisible();
    await expect(page.locator('a:has-text("Back to evaluator")')).toBeVisible();
    await expect(page.locator('text=define cek-step')).toBeVisible();
  });

  test('drill-in shows params and pure badge', async ({ page }) => {
    await loadExplorer(page, '(language.(spec.(explore.evaluator.make-cek-state)))');

    await expect(page.locator('text=control').first()).toBeVisible();
    await expect(page.locator('text=env').first()).toBeVisible();
    await expect(page.locator('text=kont').first()).toBeVisible();
    await expect(page.locator('text=pure').first()).toBeVisible();
  });
});
