/**
 * Site Crawler Tests
 *
 * Crawls the site looking for broken links, console errors, and network failures.
 * Run with: npx playwright test site-crawler.spec.ts
 *
 * These tests are designed to be run in CI to catch issues before deployment.
 */

import { test, expect } from '@playwright/test';
import {
  SiteCrawler,
  formatReport,
  loginAsUser,
  TEST_USERS,
  CrawlerOptions,
} from './utils/crawler';

// Increase timeout for crawl tests since they visit many pages
test.setTimeout(300000); // 5 minutes

const CRAWLER_OPTIONS: CrawlerOptions = {
  maxPages: 30, // Limit for CI to keep tests reasonable
  verbose: false,
  screenshotOnError: true,
  screenshotDir: 'test-results/crawler-screenshots',
  timeout: 15000,
  waitForNetworkIdle: true,
  excludePatterns: [
    /\.(pdf|zip|tar|gz|exe|dmg|pkg)$/i,
    /^mailto:/i,
    /^tel:/i,
    /^javascript:/i,
    /logout/i,
    /sign-out/i,
    // Exclude external links for faster tests
    /^https?:\/\/(?!.*lvh\.me)/i,
  ],
};

test.describe('Site Crawler - Public Pages', () => {
  test('should crawl public marketing site without errors', async ({ page, context }) => {
    const crawler = new SiteCrawler(page, context, {
      ...CRAWLER_OPTIONS,
      maxPages: 20, // Fewer pages for public site
    });

    const report = await crawler.crawl('http://lvh.me:5173');

    // Print the report
    console.log(formatReport(report));

    // Assertions
    expect(report.totalPages).toBeGreaterThan(0);

    // Filter out minor warnings that aren't real issues
    const criticalErrors = report.results.flatMap(r =>
      r.errors.filter(e => {
        // Ignore React DevTools suggestion
        if (e.message.includes('React DevTools')) return false;
        // Ignore favicon 404
        if (e.message.includes('favicon.ico')) return false;
        // Ignore hot module replacement messages
        if (e.message.includes('hot-update') || e.message.includes('hmr')) return false;
        return true;
      })
    );

    // Fail if there are critical errors
    if (criticalErrors.length > 0) {
      console.error('\n❌ Critical errors found:');
      criticalErrors.forEach(e => {
        console.error(`  - [${e.type}] ${e.url}: ${e.message}`);
      });
    }

    expect(criticalErrors.length).toBe(0);
  });
});

test.describe('Site Crawler - Platform Dashboard', () => {
  test('should crawl platform dashboard without errors', async ({ page, context }) => {
    // Login first
    const user = TEST_USERS.platformSuperuser;
    const loggedIn = await loginAsUser(page, user);
    expect(loggedIn).toBe(true);

    const crawler = new SiteCrawler(page, context, CRAWLER_OPTIONS);
    const report = await crawler.crawl('http://platform.lvh.me:5173');

    // Print the report
    console.log(formatReport(report));

    // Assertions
    expect(report.totalPages).toBeGreaterThan(0);

    // Filter out minor warnings
    const criticalErrors = report.results.flatMap(r =>
      r.errors.filter(e => {
        if (e.message.includes('React DevTools')) return false;
        if (e.message.includes('favicon.ico')) return false;
        if (e.message.includes('hot-update') || e.message.includes('hmr')) return false;
        // Ignore WebSocket connection issues in dev
        if (e.message.includes('WebSocket')) return false;
        return true;
      })
    );

    if (criticalErrors.length > 0) {
      console.error('\n❌ Critical errors found:');
      criticalErrors.forEach(e => {
        console.error(`  - [${e.type}] ${e.url}: ${e.message}`);
      });
    }

    expect(criticalErrors.length).toBe(0);
  });
});

// Uncomment and configure when tenant test users are set up
// test.describe('Site Crawler - Tenant Dashboard', () => {
//   test('should crawl tenant dashboard without errors', async ({ page, context }) => {
//     const user = TEST_USERS.businessOwner;
//     const loggedIn = await loginAsUser(page, user);
//     expect(loggedIn).toBe(true);
//
//     const crawler = new SiteCrawler(page, context, CRAWLER_OPTIONS);
//     const report = await crawler.crawl('http://demo.lvh.me:5173');
//
//     console.log(formatReport(report));
//
//     expect(report.totalPages).toBeGreaterThan(0);
//
//     const criticalErrors = report.results.flatMap(r =>
//       r.errors.filter(e => {
//         if (e.message.includes('React DevTools')) return false;
//         if (e.message.includes('favicon.ico')) return false;
//         if (e.message.includes('hot-update')) return false;
//         if (e.message.includes('WebSocket')) return false;
//         return true;
//       })
//     );
//
//     expect(criticalErrors.length).toBe(0);
//   });
// });

// test.describe('Site Crawler - Customer Portal', () => {
//   test('should crawl customer booking portal without errors', async ({ page, context }) => {
//     // Customer portal might not require auth for the booking pages
//     const crawler = new SiteCrawler(page, context, {
//       ...CRAWLER_OPTIONS,
//       maxPages: 15,
//     });
//
//     const report = await crawler.crawl('http://demo.lvh.me:5173/book');
//
//     console.log(formatReport(report));
//
//     expect(report.totalPages).toBeGreaterThan(0);
//
//     const criticalErrors = report.results.flatMap(r =>
//       r.errors.filter(e => {
//         if (e.message.includes('React DevTools')) return false;
//         if (e.message.includes('favicon.ico')) return false;
//         if (e.message.includes('hot-update')) return false;
//         return true;
//       })
//     );
//
//     expect(criticalErrors.length).toBe(0);
//   });
// });

// Quick smoke test that just checks key pages load
test.describe('Site Crawler - Quick Smoke Test', () => {
  const keyPages = [
    { name: 'Home', url: 'http://lvh.me:5173/' },
    { name: 'About', url: 'http://lvh.me:5173/about' },
    { name: 'Pricing', url: 'http://lvh.me:5173/pricing' },
    { name: 'Privacy', url: 'http://lvh.me:5173/privacy' },
    { name: 'Terms', url: 'http://lvh.me:5173/terms' },
    { name: 'Contact', url: 'http://lvh.me:5173/contact' },
  ];

  for (const { name, url } of keyPages) {
    test(`${name} page should load without errors`, async ({ page }) => {
      const errors: string[] = [];

      // Capture console errors
      page.on('console', msg => {
        if (msg.type() === 'error') {
          const text = msg.text();
          // Filter out non-critical
          if (!text.includes('React DevTools') && !text.includes('favicon')) {
            errors.push(`Console: ${text}`);
          }
        }
      });

      // Capture page errors
      page.on('pageerror', error => {
        errors.push(`Page error: ${error.message}`);
      });

      // Capture failed requests
      page.on('requestfailed', request => {
        const failedUrl = request.url();
        if (!failedUrl.includes('favicon') && !failedUrl.includes('hot-update')) {
          errors.push(`Request failed: ${failedUrl}`);
        }
      });

      await page.goto(url, { waitUntil: 'networkidle' });

      // Wait a bit for React to fully render
      await page.waitForTimeout(1000);

      // Check that page rendered something
      const bodyContent = await page.locator('body').textContent();
      expect(bodyContent?.length).toBeGreaterThan(100);

      // Report and fail if errors
      if (errors.length > 0) {
        console.error(`\n❌ Errors on ${name} page (${url}):`);
        errors.forEach(e => console.error(`  - ${e}`));
      }

      expect(errors.length).toBe(0);
    });
  }
});
