/**
 * WCAG 2.1 AAA compliance test using Playwright and axe-core
 * 
 * This script uses Playwright to load pages and axe-core to test them for accessibility issues.
 * It's an alternative to the axe-test.js script that properly injects axe-core into the page.
 */

const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');
const axeCore = require('axe-core');

// Base URL to test
const BASE_URL = process.argv[2] || 'http://localhost:8080';

// Create reports directory if it doesn't exist
const reportsDir = path.join(__dirname, '../reports');
if (!fs.existsSync(reportsDir)) {
  fs.mkdirSync(reportsDir, { recursive: true });
}

async function getPagesFromSitemap(sitemapUrl) {
  try {
    const response = await fetch(sitemapUrl);
    if (!response.ok) {
      throw new Error(`Failed to fetch sitemap: ${response.statusText}`);
    }
    const sitemapText = await response.text();
    const urls = sitemapText.match(/<loc>(.*?)<\/loc>/g) || [];
    
    return urls.map(url => {
      const urlContent = url.replace(/<\/?loc>/g, '');
      const urlObject = new URL(urlContent);
      return urlObject.pathname;
    });
  } catch (error) {
    console.error(`Error reading sitemap: ${error}`);
    // Fallback to a default list if sitemap fails
    return [
      '/',
      '/stories/',
      '/stories/open-source-success.html',
      '/stories/viperwire.html',
      '/one-pager-tools/csv-tool.html'
    ];
  }
}

async function runAxe(page, pageUrl) {
  try {
    // Use a file URL to load axe-core from a local file to avoid CSP issues
    const axeScriptPath = path.join(__dirname, 'axe-core.js');
    fs.writeFileSync(axeScriptPath, axeCore.source);
    
    // Add the script as a file
    await page.addScriptTag({ path: axeScriptPath, type: 'text/javascript' });
    
    // Run axe with WCAG 2.1 AAA rules
    const results = await page.evaluate(() => {
      if (typeof axe === 'undefined') {
        return { error: 'axe-core not loaded' };
      }
      
      return new Promise(resolve => {
        axe.run(document, { 
          runOnly: { 
            type: 'tag', 
            values: ['wcag2aaa'] 
          },
          resultTypes: ['violations', 'incomplete', 'inapplicable'],
          rules: {
            'color-contrast': { enabled: true, options: { noScroll: true } }
          }
        })
        .then(results => resolve(results))
        .catch(err => resolve({ error: err.toString() }));
      });
    });
    
    // Clean up temporary file
    fs.unlinkSync(axeScriptPath);
    
    return results;
  } catch (error) {
    console.error('Error running axe:', error);
    return { error: error.toString() };
  }
}

async function testPage(browser, pageUrl) {
  const context = await browser.newContext({
    bypassCSP: true
  });
  const page = await context.newPage();
  console.log(`Testing ${pageUrl}...`);
  
  try {
    // Navigate to the page
    await page.goto(pageUrl, { waitUntil: 'networkidle' });
    
    // Run axe-core tests
    const results = await runAxe(page, pageUrl);
    
    // Save results to file
    const fileName = pageUrl === BASE_URL ? 'index' : pageUrl.replace(BASE_URL, '').replace(/\//g, '-').replace(/^-/, '');
    const reportPath = path.join(reportsDir, `axe-${fileName || 'index'}.json`);
    fs.writeFileSync(reportPath, JSON.stringify(results, null, 2));
    
    // Log results summary
    if (results.error) {
      console.error(`Error running axe-core on ${pageUrl}:`, results.error);
      return { url: pageUrl, success: false, error: results.error };
    }
    
    const { violations, incomplete, passes, inapplicable } = results;
    console.log(`Results for ${pageUrl}:`);
    console.log(`- Violations: ${violations.length}`);
    console.log(`- Incomplete: ${incomplete.length}`);
    console.log(`- Passes: ${passes.length}`);
    console.log(`- Inapplicable: ${inapplicable.length}`);
    
    // Print violations
    if (violations.length > 0) {
      console.log('\nViolations:');
      violations.forEach((violation, i) => {
        console.log(`${i + 1}. ${violation.id} - ${violation.help} (Impact: ${violation.impact})`);
        console.log(`   Description: ${violation.description}`);
        console.log(`   Help: ${violation.helpUrl}`);
        violation.nodes.forEach(node => {
          console.log(`   - Element: ${node.html}`);
          console.log(`     Selector: ${node.target.join(', ')}`);
        });
      });
    }
    
    return { 
      url: pageUrl, 
      success: violations.length === 0, 
      violations: violations.length,
      incomplete: incomplete.length,
      passes: passes.length
    };
  } catch (error) {
    console.error(`Error testing ${pageUrl}:`, error);
    return { url: pageUrl, success: false, error: error.toString() };
  } finally {
    await page.close();
    await context.close();
  }
}

async function runTests() {
  const browser = await chromium.launch();
  const results = [];
  
  const sitemapUrl = `${BASE_URL}/sitemap.xml`;
  console.log(`Fetching pages from sitemap: ${sitemapUrl}`);
  const pagesToTest = await getPagesFromSitemap(sitemapUrl);
  console.log(`Found ${pagesToTest.length} pages to test.`);

  try {
    // Test each page
    for (const pagePath of pagesToTest) {
      const pageUrl = `${BASE_URL}${pagePath.startsWith('/') ? '' : '/'}${pagePath}`;
      const result = await testPage(browser, pageUrl);
      results.push(result);
    }
    
    // Save overall results
    const overallReport = {
      timestamp: new Date().toISOString(),
      baseUrl: BASE_URL,
      pages: results,
      summary: {
        total: results.length,
        passed: results.filter(r => r.success).length,
        failed: results.filter(r => !r.success).length
      }
    };
    
    fs.writeFileSync(path.join(reportsDir, 'axe-summary.json'), JSON.stringify(overallReport, null, 2));
    
    // Print overall summary
    console.log('\n=== Overall Summary ===');
    console.log(`Total pages tested: ${overallReport.summary.total}`);
    console.log(`Pages passed: ${overallReport.summary.passed}`);
    console.log(`Pages failed: ${overallReport.summary.failed}`);
    
    // Exit with appropriate code
    process.exit(overallReport.summary.failed > 0 ? 1 : 0);
  } catch (error) {
    console.error('Error running tests:', error);
    process.exit(1);
  } finally {
    await browser.close();
  }
}

runTests();
