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

/**
 * E2E tests for the OntoIndex web UI — exploring view features.
 *
 * Requires:
 *   - ontoindex serve running on localhost:4747 with at least one indexed repo
 *   - ontoindex-web dev server running on localhost:5173
 *
 * Skipped when servers aren't available (CI without services, etc.).
 * Set E2E=1 to force-run even without the availability check.
 */

const BACKEND_URL = process.env.BACKEND_URL ?? 'http://localhost:4747';
const FRONTEND_URL = process.env.FRONTEND_URL ?? 'http://localhost:5173';

test.beforeAll(async () => {
  if (process.env.E2E) return;
  try {
    const [backendRes, frontendRes] = await Promise.allSettled([
      fetch(`${BACKEND_URL}/api/repos`),
      fetch(FRONTEND_URL),
    ]);
    if (
      backendRes.status === 'rejected' ||
      (backendRes.status === 'fulfilled' && !backendRes.value.ok)
    ) {
      test.skip(true, 'ontoindex serve not available on :4747');
      return;
    }
    if (
      frontendRes.status === 'rejected' ||
      (frontendRes.status === 'fulfilled' && !frontendRes.value.ok)
    ) {
      test.skip(true, 'Vite dev server not available on :5173');
      return;
    }
    // Check there's at least one indexed repo
    if (backendRes.status === 'fulfilled') {
      const repos = await backendRes.value.json();
      if (!repos.length) {
        test.skip(true, 'No indexed repos — run ontoindex analyze first');
        return;
      }
    }
  } catch {
    test.skip(true, 'servers not available');
  }
});

/**
 * Wait for the server-detection flow to complete.
 *
 * The app auto-detects the server, then either:
 *   - shows the landing screen when indexed repos exist, or
 *   - goes straight into analyze onboarding when there are zero repos.
 *
 * For these tests we require at least one indexed repo, so pick the first
 * landing card when present and then wait for the exploring view.
 */
async function waitForGraphLoaded(page: import('@playwright/test').Page) {
  await page.goto('/');

  const landingCards = page.locator('[data-testid="landing-repo-card"]');
  const preferredLandingCard = landingCards
    .filter({ hasText: /OntoIndex|local-integration/ })
    .first();
  try {
    await landingCards.first().waitFor({ state: 'visible', timeout: 15_000 });
    const landingCard =
      (await preferredLandingCard.count()) > 0 ? preferredLandingCard : landingCards.first();
    await landingCard.click();
  } catch {
    // Landing screen may not appear (e.g. ?server auto-connect)
  }

  const statusBar = page.getByRole('contentinfo');
  await expect(statusBar.getByText('Ready', { exact: true })).toBeVisible({ timeout: 45_000 });
  await expect(statusBar).toContainText(/nodes/, {
    timeout: 20_000,
  });
}

test.describe('Server Connection & Graph Loading', () => {
  test('selects a repo from landing and loads graph', async ({ page }) => {
    await waitForGraphLoaded(page);
  });
});

test.describe('Nexus AI', () => {
  test('panel opens and agent initializes without error', async ({ page }) => {
    await waitForGraphLoaded(page);

    await page.getByRole('button', { name: 'Nexus AI' }).click();
    await expect(page.getByText('Ask me anything')).toBeVisible({ timeout: 15_000 });

    const errorBanner = page.getByText('Database not ready');
    expect(await errorBanner.isVisible().catch(() => false)).toBe(false);
  });
});

test.describe('Processes Panel', () => {
  test('shows process list and View button works', async ({ page }) => {
    await waitForGraphLoaded(page);

    await page.getByRole('button', { name: 'Nexus AI' }).click();
    await page.getByText('Processes').click();

    await expect(page.locator('[data-testid="process-list-loaded"]')).toBeVisible({
      timeout: 15_000,
    });

    const processRow = page.locator('[data-testid="process-row"]').first();
    await expect(processRow).toBeVisible({ timeout: 10_000 });
    await processRow.hover();

    const viewBtn = processRow.locator('[data-testid="process-view-button"]');
    await viewBtn.waitFor({ state: 'visible', timeout: 5_000 });
    await viewBtn.click();
    await expect(page.locator('[data-testid="process-modal"]')).toBeVisible({ timeout: 5_000 });
  });

  test('lightbulb highlights nodes in graph', async ({ page }) => {
    await waitForGraphLoaded(page);

    await page.getByRole('button', { name: 'Nexus AI' }).click();
    await page.getByText('Processes').click();
    await expect(page.locator('[data-testid="process-list-loaded"]')).toBeVisible({
      timeout: 15_000,
    });

    const processRow = page.locator('[data-testid="process-row"]').first();
    await expect(processRow).toBeVisible({ timeout: 10_000 });
    await processRow.hover();

    const lightbulb = processRow.locator('[data-testid="process-highlight-button"]');
    await lightbulb.waitFor({ state: 'visible', timeout: 5_000 });
    await lightbulb.click();
    await expect(processRow).toHaveClass(/bg-amber-950/, { timeout: 5_000 });
  });
});

test.describe('Turn Off All Highlights', () => {
  test('selecting a node dims others, button clears it', async ({ page }) => {
    await waitForGraphLoaded(page);

    await expect(page.locator('canvas').first()).toBeVisible({ timeout: 10_000 });

    const fileItem = page.getByText('package.json').first();
    await expect(fileItem).toBeVisible({ timeout: 10_000 });
    await fileItem.click();

    const highlightToggle = page.locator('[data-testid="ai-highlights-toggle"]');
    await expect(highlightToggle).toHaveAttribute('title', 'Turn off all highlights', {
      timeout: 5_000,
    });

    await highlightToggle.click();
    await expect(highlightToggle).toHaveAttribute('title', 'Turn on AI highlights', {
      timeout: 5_000,
    });
  });
});
