/**
 * Smoke suite — Web
 *
 * Runs after every deploy to verify critical frontend pages load and
 * render key UI elements.  Tagged with @smoke for targeted execution:
 *
 *   npx playwright test --project=web --grep @smoke
 *
 * Tests avoid user interactions that require a live API/auth session so
 * they remain fast and resilient in staging environments.
 */
import { test, expect } from '@playwright/test';

// ── Homepage ──────────────────────────────────────────────────────────────────

test('@smoke homepage loads', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveTitle(/.+/);
  // Search bar or hero section must be visible
  const searchInput = page.getByRole('searchbox').or(page.getByPlaceholder(/tìm kiếm|search/i));
  await expect(searchInput.first()).toBeVisible({ timeout: 10_000 });
});

// ── Auth pages ────────────────────────────────────────────────────────────────

test('@smoke login page renders form', async ({ page }) => {
  await page.goto('/login');
  await expect(page.getByRole('heading', { name: /đăng nhập/i })).toBeVisible();
  await expect(page.getByLabel(/số điện thoại/i)).toBeVisible();
  await expect(page.getByLabel(/mật khẩu/i)).toBeVisible();
  await expect(page.getByRole('button', { name: /đăng nhập/i })).toBeVisible();
});

test('@smoke register page renders form', async ({ page }) => {
  await page.goto('/register');
  await expect(page.getByRole('heading', { name: /đăng ký/i })).toBeVisible();
  await expect(page.getByLabel(/số điện thoại/i)).toBeVisible();
});

// ── Listings ──────────────────────────────────────────────────────────────────

test('@smoke listings page loads without JS errors', async ({ page }) => {
  const errors: string[] = [];
  page.on('pageerror', (err) => errors.push(err.message));

  await page.goto('/listings');
  // Allow time for async data loading
  await page.waitForLoadState('networkidle', { timeout: 15_000 }).catch(() => {
    // networkidle may not be reached if polling; continue
  });

  // Page must not show an unhandled error boundary
  const errorHeading = page.getByRole('heading', { name: /500|something went wrong|lỗi/i });
  await expect(errorHeading).not.toBeVisible();

  // Filter JS errors that are not related to missing env vars in test
  const fatalErrors = errors.filter(
    (e) => !e.includes('NEXT_PUBLIC') && !e.includes('mapbox'),
  );
  expect(fatalErrors).toHaveLength(0);
});

// ── Search ────────────────────────────────────────────────────────────────────

test('@smoke search page is accessible', async ({ page }) => {
  await page.goto('/search?q=apartment');
  await expect(page).not.toHaveTitle(/404|not found/i);
  // Some results container or empty-state must be present
  const container = page
    .locator('[data-testid="search-results"]')
    .or(page.locator('[data-testid="empty-state"]'))
    .or(page.getByText(/kết quả|results|không tìm thấy/i));
  // Be lenient — search service may be unavailable in staging
  await page.waitForTimeout(3000);
  // Just confirm no crash
  const errorBoundary = page.getByRole('heading', { name: /500|server error/i });
  await expect(errorBoundary).not.toBeVisible();
});

// ── Listing Detail ────────────────────────────────────────────────────────────

test('@smoke listing detail page handles missing id gracefully', async ({ page }) => {
  const res = await page.goto('/listings/nonexistent-smoke-test-id');
  // Should render 404 page, not crash with 500
  const status = res?.status();
  if (status && status >= 500) {
    throw new Error(`Listing detail returned ${status} for unknown ID (expected 404)`);
  }
});

// ── Static / infra ────────────────────────────────────────────────────────────

test('@smoke no console errors on login page', async ({ page }) => {
  const consoleErrors: string[] = [];
  page.on('console', (msg) => {
    if (msg.type() === 'error') consoleErrors.push(msg.text());
  });

  await page.goto('/login');
  await page.waitForLoadState('domcontentloaded');

  // Filter noise from third-party scripts / mapbox in test env
  const meaningful = consoleErrors.filter(
    (e) =>
      !e.includes('mapbox') &&
      !e.includes('NEXT_PUBLIC') &&
      !e.includes('Failed to load resource') &&
      !e.includes('net::ERR'),
  );
  expect(meaningful).toHaveLength(0);
});
