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

/**
 * WCAG Audit Script
 *
 * 1. Fetches sitemap.xml from the target URL
 * 2. Extracts all URLs
 * 3. Runs pa11y-ci on those URLs
 */

const targetUrl = process.argv[2] || process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
const limit = process.env.PAGESPEED_LIMIT ? parseInt(process.env.PAGESPEED_LIMIT) : 20;
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'klz2026';

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

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

    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.`,
      );
      const home = urls.filter((u) => u.endsWith('/de') || u.endsWith('/en') || u === targetUrl);
      const others = urls.filter((u) => !home.includes(u));
      urls = [...home, ...others.slice(0, limit - home.length)];
    }

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

    // 2. Prepare pa11y-ci config
    const baseConfigPath = path.join(process.cwd(), '.pa11yci.json');
    let baseConfig: any = { defaults: {} };
    if (fs.existsSync(baseConfigPath)) {
      baseConfig = JSON.parse(fs.readFileSync(baseConfigPath, 'utf8'));
    }

    // Extract domain for cookie
    const urlObj = new URL(targetUrl);
    const domain = urlObj.hostname;

    // Update config with discovered URLs and gatekeeper cookie
    const tempConfig = {
      ...baseConfig,
      defaults: {
        ...baseConfig.defaults,
        threshold: 0, // Force threshold to 0 so all errors are shown in JSON
        runners: ['axe'],
        ignore: [...(baseConfig.defaults?.ignore || []), 'color-contrast'],
        chromeLaunchConfig: {
          ...baseConfig.defaults?.chromeLaunchConfig,
          ...(process.env.CHROME_PATH ? { executablePath: process.env.CHROME_PATH } : {}),
          args: [
            ...(baseConfig.defaults?.chromeLaunchConfig?.args || []),
            '--no-sandbox',
            '--disable-setuid-sandbox',
          ],
        },
        headers: {
          Cookie: `klz_gatekeeper_session=${gatekeeperPassword}`,
        },
        timeout: 60000, // Increase timeout for slower pages
      },
      urls: urls,
    };

    // Create output directory
    const outputDir = path.join(process.cwd(), '.pa11yci');
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }

    const tempConfigPath = path.join(outputDir, 'config.temp.json');
    const reportPath = path.join(outputDir, 'report.json');
    fs.writeFileSync(tempConfigPath, JSON.stringify(tempConfig, null, 2));

    // 3. Execute pa11y-ci
    console.log(`\n💻 Executing pa11y-ci...`);
    const pa11yCommand = `npx pa11y-ci --config .pa11yci/config.temp.json --reporter json > .pa11yci/report.json`;

    try {
      execSync(pa11yCommand, {
        encoding: 'utf8',
        stdio: 'inherit',
      });
    } catch (err: any) {
      // pa11y-ci exits with non-zero if issues are found, which is expected
    }

    // 4. Summarize Results
    if (fs.existsSync(reportPath)) {
      const reportData = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
      console.log(`\n📊 WCAG Audit Summary:\n`);

      const summaryTable = Object.keys(reportData.results).map((url) => {
        const results = reportData.results[url];
        // Results might have errors or just a top level message if it crashed
        let errors = 0;
        let warnings = 0;
        let notices = 0;

        if (Array.isArray(results)) {
          // pa11y action execution errors come as objects with a message but no type
          const actionErrors = results.filter((r: any) => !r.type && r.message).length;
          errors = results.filter((r: any) => r.type === 'error').length + actionErrors;
          warnings = results.filter((r: any) => r.type === 'warning').length;
          notices = results.filter((r: any) => r.type === 'notice').length;
        }

        // Clean URL for display
        const displayUrl = url.replace(targetUrl, '') || '/';

        return {
          URL: displayUrl.length > 50 ? displayUrl.substring(0, 47) + '...' : displayUrl,
          Errors: errors,
          Warnings: warnings,
          Notices: notices,
          Status: errors === 0 ? '✅' : '❌',
        };
      });

      console.table(summaryTable);

      const totalErrors = summaryTable.reduce((acc, curr) => acc + curr.Errors, 0);
      const totalPages = summaryTable.length;
      const cleanPages = summaryTable.filter((p) => p.Errors === 0).length;

      console.log(`\n📈 Result: ${cleanPages}/${totalPages} pages are error-free.`);
      if (totalErrors > 0) {
        console.log(`   Total Errors discovered: ${totalErrors}`);
        process.exitCode = 1;
      }
    }

    console.log(`\n✨ WCAG Audit completed!`);
  } catch (error: any) {
    console.error(`\n❌ Error during WCAG Audit:`);
    if (axios.isAxiosError(error)) {
      console.error(`Status: ${error.response?.status}`);
      console.error(`URL: ${error.config?.url}`);
    } else {
      console.error(error.message);
    }
    process.exit(1);
  } finally {
    // Clean up temp config file, keep report
    const tempConfigPath = path.join(process.cwd(), '.pa11yci/config.temp.json');
    if (fs.existsSync(tempConfigPath)) fs.unlinkSync(tempConfigPath);
  }
}

main();
