import axios from 'axios';
import * as cheerio from 'cheerio';
import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';

/**
 * PageSpeed Test Script
 *
 * 1. Fetches sitemap.xml from the target URL
 * 2. Extracts all URLs
 * 3. Runs Lighthouse CI on those URLs
 */

const targetUrl =
  process.argv.find((arg) => !arg.startsWith('--') && arg.startsWith('http')) ||
  process.env.NEXT_PUBLIC_BASE_URL ||
  process.env.LHCI_URL ||
  'http://localhost:3000';
const limit = process.env.PAGESPEED_LIMIT ? parseInt(process.env.PAGESPEED_LIMIT) : 20; // Default limit to avoid infinite runs
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';

async function main() {
  console.log(`\n🚀 Starting PageSpeed test for: ${targetUrl}`);
  console.log(`📊 Limit: ${limit} pages\n`);

  try {
    // 1. Fetch Sitemap
    const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`;
    console.log(`📥 Fetching sitemap from ${sitemapUrl}...`);

    // We might need to bypass gatekeeper for the sitemap fetch too
    const response = await axios.get(sitemapUrl, {
      headers: {
        Cookie: `klz_gatekeeper_session=${gatekeeperPassword}`,
      },
      validateStatus: (status) => status < 400,
    });

    const $ = cheerio.load(response.data, { xmlMode: true });
    let urls = $('url loc')
      .map((i, el) => $(el).text())
      .get();

    // Cleanup, filter and normalize domains to targetUrl
    const urlPattern = /https?:\/\/[^\/]+/;
    urls = [...new Set(urls)]
      .filter((u) => u.startsWith('http'))
      .map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, '')))
      .sort();

    console.log(`✅ Found ${urls.length} URLs in sitemap.`);

    if (urls.length === 0) {
      console.error('❌ No URLs found in sitemap. Is the site up?');
      process.exit(1);
    }

    if (urls.length > limit) {
      console.log(
        `⚠️  Too many pages (${urls.length}). Limiting to ${limit} representative pages.`,
      );
      // Try to pick a variety: home, some products, some blog posts
      const homeEN = urls.filter((u) => u.endsWith('/en') || u === targetUrl);
      const homeDE = urls.filter((u) => u.endsWith('/de'));
      const others = urls.filter((u) => !homeEN.includes(u) && !homeDE.includes(u));
      urls = [...homeEN, ...homeDE, ...others.slice(0, limit - (homeEN.length + homeDE.length))];
    }

    console.log(`🧪 Pages to be tested:`);
    urls.forEach((u) => console.log(`   - ${u}`));

    // 2. Prepare LHCI command
    // We use --collect.url multiple times
    const urlArgs = urls.map((u) => `--collect.url="${u}"`).join(' ');

    // Handle authentication for staging/testing
    // Lighthouse can set cookies via --collect.settings.extraHeaders
    const extraHeaders = JSON.stringify({
      Cookie: `klz_gatekeeper_session=${gatekeeperPassword}`,
    });

    // Detect Chrome path from Puppeteer installation if not provided
    let chromePath = process.env.CHROME_PATH || process.env.PUPPETEER_EXECUTABLE_PATH;
    if (!chromePath) {
      try {
        console.log('🔍 Attempting to detect Puppeteer Chrome path...');
        const puppeteerInfo = execSync('npx puppeteer browsers latest chrome', {
          encoding: 'utf8',
        });
        console.log(`📦 Puppeteer info: ${puppeteerInfo}`);
        const match = puppeteerInfo.match(/executablePath: (.*)/);
        if (match && match[1]) {
          chromePath = match[1].trim();
          console.log(`✅ Detected Puppeteer Chrome at: ${chromePath}`);
        }
      } catch (e: any) {
        console.warn(`⚠️ Could not detect Puppeteer Chrome path via command: ${e.message}`);
      }

      // Fallback to known paths if still not found
      if (!chromePath) {
        const fallbacks = [
          '/root/.cache/puppeteer/chrome/linux-145.0.7632.77/chrome-linux64/chrome',
          '/home/runner/.cache/puppeteer/chrome/linux-145.0.7632.77/chrome-linux64/chrome',
          path.join(
            process.cwd(),
            'node_modules',
            '.puppeteer',
            'chrome',
            'linux-145.0.7632.77',
            'chrome-linux64',
            'chrome',
          ),
        ];

        for (const fallback of fallbacks) {
          if (fs.existsSync(fallback)) {
            chromePath = fallback;
            console.log(`✅ Found Puppeteer Chrome at fallback: ${chromePath}`);
            break;
          }
        }
      }
    } else {
      console.log(`ℹ️ Using existing Chrome path: ${chromePath}`);
    }

    if (!chromePath) {
      console.warn('❌ CHROME_PATH is still undefined. Lighthouse might fail.');
    }

    const chromePathArg = chromePath ? `--collect.chromePath="${chromePath}"` : '';

    // Clean up old reports
    if (fs.existsSync('.lighthouseci')) {
      fs.rmSync('.lighthouseci', { recursive: true, force: true });
    }

    // Using a more robust way to execute and capture output
    // We use a puppeteer script to set cookies which is more reliable than extraHeaders for LHCI
    const lhciCommand = `npx lhci collect ${urlArgs} ${chromePathArg} --config=config/lighthouserc.json --collect.puppeteerScript="scripts/lhci-puppeteer-setup.js" --collect.settings.chromeFlags="--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage" && npx lhci assert --config=config/lighthouserc.json`;

    console.log(`💻 Executing LHCI with CHROME_PATH="${chromePath}" and Puppeteer Auth...`);

    try {
      execSync(lhciCommand, {
        encoding: 'utf8',
        stdio: 'inherit',
        env: { ...process.env, CHROME_PATH: chromePath },
      });
    } catch (err: any) {
      console.warn('⚠️ LHCI assertion finished with warnings or errors.');
      // We continue to show the table even if assertions failed
    }

    // 3. Summarize Results (Local & Independent)
    const manifestPath = path.join(process.cwd(), '.lighthouseci', 'manifest.json');
    if (fs.existsSync(manifestPath)) {
      const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
      console.log(`\n📊 PageSpeed Summary (FOSS - Local Report):\n`);

      const summaryTable = manifest.map((entry: any) => {
        const s = entry.summary;
        return {
          URL: entry.url.replace(targetUrl, ''),
          Perf: Math.round(s.performance * 100),
          Acc: Math.round(s.accessibility * 100),
          BP: Math.round(s['best-practices'] * 100),
          SEO: Math.round(s.seo * 100),
        };
      });

      console.table(summaryTable);

      // Calculate Average
      const avg = {
        Perf: Math.round(
          summaryTable.reduce((acc: any, curr: any) => acc + curr.Perf, 0) / summaryTable.length,
        ),
        Acc: Math.round(
          summaryTable.reduce((acc: any, curr: any) => acc + curr.Acc, 0) / summaryTable.length,
        ),
        BP: Math.round(
          summaryTable.reduce((acc: any, curr: any) => acc + curr.BP, 0) / summaryTable.length,
        ),
        SEO: Math.round(
          summaryTable.reduce((acc: any, curr: any) => acc + curr.SEO, 0) / summaryTable.length,
        ),
      };

      console.log(`\n📈 Average Scores:`);
      console.log(`   Performance:   ${avg.Perf > 90 ? '✅' : '⚠️'} ${avg.Perf}`);
      console.log(`   Accessibility: ${avg.Acc > 90 ? '✅' : '⚠️'} ${avg.Acc}`);
      console.log(`   Best Practices: ${avg.BP > 90 ? '✅' : '⚠️'} ${avg.BP}`);
      console.log(`   SEO:           ${avg.SEO > 90 ? '✅' : '⚠️'} ${avg.SEO}`);
    }

    console.log(`\n✨ PageSpeed tests completed successfully!`);
  } catch (error: any) {
    console.error(`\n❌ Error during PageSpeed test:`);
    if (axios.isAxiosError(error)) {
      console.error(`Status: ${error.response?.status}`);
      console.error(`StatusText: ${error.response?.statusText}`);
      console.error(`URL: ${error.config?.url}`);
    } else {
      console.error(error.message);
    }
    process.exit(1);
  }
}

main();
