/**
 * Axe Accessibility Audit Script
 *
 * This script runs axe-core accessibility scans on all main pages of the portfolio site.
 * It generates a comprehensive report with WCAG references.
 *
 * Usage:
 *   node scripts/axe-accessibility-audit.js
 *
 * Prerequisites:
 *   - Development server running on http://localhost:3000
 *   - Install deps: npm install puppeteer @axe-core/puppeteer --no-save
 */

const { AxePuppeteer } = require('@axe-core/puppeteer');
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');

// Configuration
const BASE_URL = 'http://localhost:3000';
const LOCALES = ['de', 'en', 'sr'];
const OUTPUT_DIR = path.join(__dirname, '..', '.auto-claude', 'specs', '001-suche-nach-optimierungsvorschl-gen');

// Pages to audit (main public pages)
const PAGES = [
  { path: '', name: 'Home' },
  { path: '/about', name: 'About' },
  { path: '/blog', name: 'Blog Index' },
  { path: '/contact', name: 'Contact' },
  { path: '/leistungen', name: 'Services' },
  { path: '/portfolio', name: 'Portfolio Index' },
  { path: '/imprint', name: 'Imprint' },
  { path: '/privacy', name: 'Privacy' },
  { path: '/terms', name: 'Terms' },
];

// WCAG 2.1 Impact mapping
const IMPACT_ORDER = {
  'critical': 0,
  'serious': 1,
  'moderate': 2,
  'minor': 3
};

const WCAG_TAGS = {
  'wcag2a': 'WCAG 2.0 Level A',
  'wcag2aa': 'WCAG 2.0 Level AA',
  'wcag2aaa': 'WCAG 2.0 Level AAA',
  'wcag21a': 'WCAG 2.1 Level A',
  'wcag21aa': 'WCAG 2.1 Level AA',
  'wcag22aa': 'WCAG 2.2 Level AA',
  'best-practice': 'Best Practice'
};

/**
 * Run axe audit on a single page
 */
async function auditPage(browser, url, pageName) {
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 800 });

  console.log(`  Scanning: ${url}`);

  try {
    await page.goto(url, { waitUntil: 'networkidle0', timeout: 30000 });

    // Wait for dynamic content to load
    await page.waitForTimeout(1000);

    // Run axe analysis
    const results = await new AxePuppeteer(page)
      .withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice'])
      .analyze();

    await page.close();

    return {
      url,
      pageName,
      timestamp: new Date().toISOString(),
      violations: results.violations,
      passes: results.passes.length,
      incomplete: results.incomplete,
      inapplicable: results.inapplicable.length
    };
  } catch (error) {
    await page.close();
    return {
      url,
      pageName,
      timestamp: new Date().toISOString(),
      error: error.message,
      violations: [],
      passes: 0,
      incomplete: [],
      inapplicable: 0
    };
  }
}

/**
 * Format violations for markdown output
 */
function formatViolation(violation) {
  const wcagTags = violation.tags
    .filter(tag => tag.startsWith('wcag') || tag === 'best-practice')
    .map(tag => WCAG_TAGS[tag] || tag)
    .join(', ');

  const nodes = violation.nodes.map(node => ({
    html: node.html.substring(0, 200),
    target: node.target.join(', '),
    failureSummary: node.failureSummary
  }));

  return {
    id: violation.id,
    impact: violation.impact,
    description: violation.description,
    help: violation.help,
    helpUrl: violation.helpUrl,
    wcagTags,
    nodeCount: nodes.length,
    nodes: nodes.slice(0, 5) // Limit to first 5 examples
  };
}

/**
 * Aggregate violations across all pages
 */
function aggregateViolations(allResults) {
  const violationMap = new Map();

  for (const result of allResults) {
    if (result.error) continue;

    for (const violation of result.violations) {
      const key = violation.id;

      if (!violationMap.has(key)) {
        violationMap.set(key, {
          ...formatViolation(violation),
          affectedPages: [],
          totalInstances: 0
        });
      }

      const aggregated = violationMap.get(key);
      aggregated.affectedPages.push({
        url: result.url,
        pageName: result.pageName,
        instances: violation.nodes.length
      });
      aggregated.totalInstances += violation.nodes.length;
    }
  }

  // Sort by impact severity, then by total instances
  return Array.from(violationMap.values()).sort((a, b) => {
    const impactDiff = IMPACT_ORDER[a.impact] - IMPACT_ORDER[b.impact];
    if (impactDiff !== 0) return impactDiff;
    return b.totalInstances - a.totalInstances;
  });
}

/**
 * Generate markdown report
 */
function generateMarkdownReport(allResults, aggregatedViolations) {
  const timestamp = new Date().toISOString();

  // Calculate statistics
  const totalPages = allResults.filter(r => !r.error).length;
  const errorPages = allResults.filter(r => r.error).length;
  const totalViolations = aggregatedViolations.length;
  const totalInstances = aggregatedViolations.reduce((sum, v) => sum + v.totalInstances, 0);

  const bySeverity = {
    critical: aggregatedViolations.filter(v => v.impact === 'critical'),
    serious: aggregatedViolations.filter(v => v.impact === 'serious'),
    moderate: aggregatedViolations.filter(v => v.impact === 'moderate'),
    minor: aggregatedViolations.filter(v => v.impact === 'minor')
  };

  let report = `# Axe Accessibility Audit Report

**Generated:** ${timestamp}
**Tool:** axe-core via @axe-core/puppeteer
**Standards:** WCAG 2.0 A/AA, WCAG 2.1 A/AA, Best Practices

---

## Executive Summary

| Metric | Value |
|--------|-------|
| Pages Scanned | ${totalPages} |
| Pages with Errors | ${errorPages} |
| Unique Violations | ${totalViolations} |
| Total Instances | ${totalInstances} |
| Critical Issues | ${bySeverity.critical.length} |
| Serious Issues | ${bySeverity.serious.length} |
| Moderate Issues | ${bySeverity.moderate.length} |
| Minor Issues | ${bySeverity.minor.length} |

`;

  // Severity breakdown
  report += `### Severity Distribution

`;

  if (bySeverity.critical.length > 0) {
    report += `🔴 **Critical (${bySeverity.critical.length}):** ${bySeverity.critical.map(v => v.id).join(', ')}\n\n`;
  } else {
    report += `✅ **Critical (0):** No critical issues found\n\n`;
  }

  if (bySeverity.serious.length > 0) {
    report += `🟠 **Serious (${bySeverity.serious.length}):** ${bySeverity.serious.map(v => v.id).join(', ')}\n\n`;
  } else {
    report += `✅ **Serious (0):** No serious issues found\n\n`;
  }

  if (bySeverity.moderate.length > 0) {
    report += `🟡 **Moderate (${bySeverity.moderate.length}):** ${bySeverity.moderate.map(v => v.id).join(', ')}\n\n`;
  } else {
    report += `✅ **Moderate (0):** No moderate issues found\n\n`;
  }

  if (bySeverity.minor.length > 0) {
    report += `🟢 **Minor (${bySeverity.minor.length}):** ${bySeverity.minor.map(v => v.id).join(', ')}\n\n`;
  } else {
    report += `✅ **Minor (0):** No minor issues found\n\n`;
  }

  report += `---

## Page-by-Page Results

`;

  for (const result of allResults) {
    const locale = result.url.split('/')[3] || 'root';
    const violationCount = result.violations?.length || 0;
    const status = result.error ? '❌ Error' : (violationCount === 0 ? '✅ Pass' : `⚠️ ${violationCount} issues`);

    report += `### ${result.pageName} (${locale.toUpperCase()})

**URL:** ${result.url}
**Status:** ${status}
`;

    if (result.error) {
      report += `**Error:** ${result.error}\n\n`;
    } else {
      report += `**Passes:** ${result.passes} | **Violations:** ${violationCount} | **Incomplete:** ${result.incomplete.length}\n\n`;

      if (violationCount > 0) {
        report += `**Issues found:**\n`;
        for (const v of result.violations) {
          report += `- \`${v.id}\` (${v.impact}): ${v.help} - ${v.nodes.length} instance(s)\n`;
        }
        report += '\n';
      }
    }
  }

  report += `---

## Detailed Violations

`;

  for (const violation of aggregatedViolations) {
    const impactEmoji = {
      'critical': '🔴',
      'serious': '🟠',
      'moderate': '🟡',
      'minor': '🟢'
    }[violation.impact];

    report += `### ${impactEmoji} ${violation.id}

**Impact:** ${violation.impact.toUpperCase()}
**WCAG:** ${violation.wcagTags || 'N/A'}
**Help:** ${violation.help}
**Total Instances:** ${violation.totalInstances}
**Documentation:** [Deque ${violation.id}](${violation.helpUrl})

**Description:** ${violation.description}

**Affected Pages:**
`;

    for (const page of violation.affectedPages) {
      report += `- ${page.pageName} (${page.url}): ${page.instances} instance(s)\n`;
    }

    report += '\n**Example Elements:**\n\n```html\n';
    for (const node of violation.nodes.slice(0, 3)) {
      report += `<!-- Target: ${node.target} -->\n`;
      report += `${node.html}\n\n`;
    }
    report += '```\n\n';

    if (violation.nodes[0]?.failureSummary) {
      report += `**Fix:** ${violation.nodes[0].failureSummary}\n\n`;
    }

    report += `---\n\n`;
  }

  // Recommendations section
  report += `## Recommendations

### Immediate Actions (Critical & Serious)

`;

  for (const v of [...bySeverity.critical, ...bySeverity.serious]) {
    report += `1. **Fix \`${v.id}\`**: ${v.help} - Affects ${v.affectedPages.length} page(s), ${v.totalInstances} total instance(s)\n`;
  }

  if (bySeverity.critical.length === 0 && bySeverity.serious.length === 0) {
    report += `✅ No critical or serious issues to fix immediately.\n`;
  }

  report += `
### Short-term Improvements (Moderate)

`;

  for (const v of bySeverity.moderate) {
    report += `1. **Fix \`${v.id}\`**: ${v.help} - Affects ${v.affectedPages.length} page(s)\n`;
  }

  if (bySeverity.moderate.length === 0) {
    report += `✅ No moderate issues to address.\n`;
  }

  report += `
### Nice-to-have (Minor & Best Practices)

`;

  for (const v of bySeverity.minor) {
    report += `1. **Consider \`${v.id}\`**: ${v.help}\n`;
  }

  if (bySeverity.minor.length === 0) {
    report += `✅ No minor issues found.\n`;
  }

  report += `
---

## WCAG Compliance Summary

Based on axe automated testing, the following WCAG conformance levels have been evaluated:

| Level | Status | Notes |
|-------|--------|-------|
| WCAG 2.0 A | ${bySeverity.critical.length === 0 ? '✅ Pass' : '❌ Fail'} | ${bySeverity.critical.length > 0 ? `${bySeverity.critical.length} critical violations` : 'No critical violations'} |
| WCAG 2.0 AA | ${(bySeverity.critical.length + bySeverity.serious.length) === 0 ? '✅ Pass' : '⚠️ Issues'} | ${(bySeverity.critical.length + bySeverity.serious.length) > 0 ? `${bySeverity.critical.length + bySeverity.serious.length} issues` : 'No serious violations'} |
| WCAG 2.1 AA | ${(bySeverity.critical.length + bySeverity.serious.length) === 0 ? '✅ Pass' : '⚠️ Issues'} | Same as above |

**Note:** Automated testing can only catch ~30-40% of accessibility issues. Manual testing for keyboard navigation,
screen reader compatibility, and cognitive accessibility is also required for full WCAG compliance.

---

## Testing Methodology

- **Tool:** axe-core via @axe-core/puppeteer
- **Browser:** Chromium (Puppeteer)
- **Viewport:** 1280x800 (Desktop)
- **Standards Tested:** wcag2a, wcag2aa, wcag21a, wcag21aa, best-practice
- **Locales Tested:** German (de), English (en), Serbian (sr)

## Next Steps

1. Address all critical and serious violations first
2. Fix moderate issues for full WCAG 2.1 AA compliance
3. Perform manual keyboard navigation testing
4. Test with screen readers (NVDA, VoiceOver)
5. Review color contrast manually for custom components
6. Test with real users with disabilities if possible
`;

  return report;
}

/**
 * Main execution
 */
async function main() {
  console.log('🔍 Axe Accessibility Audit Starting...\n');

  // Check if dev server is running
  try {
    const http = require('http');
    await new Promise((resolve, reject) => {
      http.get(BASE_URL, (res) => {
        if (res.statusCode === 200 || res.statusCode === 301 || res.statusCode === 302) {
          resolve();
        } else {
          reject(new Error(`Server returned ${res.statusCode}`));
        }
      }).on('error', reject);
    });
  } catch (error) {
    console.error('❌ Development server not running!');
    console.error('   Please start the server with: pnpm dev');
    process.exit(1);
  }

  console.log('✅ Development server detected\n');

  // Launch browser
  const browser = await puppeteer.launch({
    headless: 'new',
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });

  const allResults = [];

  try {
    // Test each locale and page combination
    for (const locale of LOCALES) {
      console.log(`\n📍 Scanning locale: ${locale.toUpperCase()}`);

      for (const page of PAGES) {
        const url = `${BASE_URL}/${locale}${page.path}`;
        const result = await auditPage(browser, url, page.name);
        allResults.push(result);
      }
    }

    console.log('\n\n📊 Processing results...');

    // Aggregate violations
    const aggregatedViolations = aggregateViolations(allResults);

    // Generate report
    const report = generateMarkdownReport(allResults, aggregatedViolations);

    // Save report
    const reportPath = path.join(OUTPUT_DIR, 'axe-accessibility-audit.md');
    fs.writeFileSync(reportPath, report);

    // Save JSON data for further analysis
    const jsonPath = path.join(OUTPUT_DIR, 'axe-accessibility-audit.json');
    fs.writeFileSync(jsonPath, JSON.stringify({
      timestamp: new Date().toISOString(),
      summary: {
        pagesScanned: allResults.filter(r => !r.error).length,
        uniqueViolations: aggregatedViolations.length,
        totalInstances: aggregatedViolations.reduce((sum, v) => sum + v.totalInstances, 0),
        bySeverity: {
          critical: aggregatedViolations.filter(v => v.impact === 'critical').length,
          serious: aggregatedViolations.filter(v => v.impact === 'serious').length,
          moderate: aggregatedViolations.filter(v => v.impact === 'moderate').length,
          minor: aggregatedViolations.filter(v => v.impact === 'minor').length
        }
      },
      violations: aggregatedViolations,
      pageResults: allResults
    }, null, 2));

    console.log(`\n✅ Audit complete!`);
    console.log(`   Report: ${reportPath}`);
    console.log(`   JSON:   ${jsonPath}`);

    // Print summary
    console.log('\n📈 Summary:');
    console.log(`   Pages scanned: ${allResults.filter(r => !r.error).length}`);
    console.log(`   Unique violations: ${aggregatedViolations.length}`);
    console.log(`   Critical: ${aggregatedViolations.filter(v => v.impact === 'critical').length}`);
    console.log(`   Serious: ${aggregatedViolations.filter(v => v.impact === 'serious').length}`);
    console.log(`   Moderate: ${aggregatedViolations.filter(v => v.impact === 'moderate').length}`);
    console.log(`   Minor: ${aggregatedViolations.filter(v => v.impact === 'minor').length}`);

  } finally {
    await browser.close();
  }
}

main().catch(error => {
  console.error('Fatal error:', error);
  process.exit(1);
});
