"use strict";
/**
 * Report Generator Service
 * Generates HTML accessibility reports
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReportGenerator = void 0;
const promises_1 = __importDefault(require("fs/promises"));
const path_1 = __importDefault(require("path"));
const logger_1 = require("@bluefly/llmcli/utils/logger");
class ReportGenerator {
    constructor() { }
    static getInstance() {
        if (!ReportGenerator.instance) {
            ReportGenerator.instance = new ReportGenerator();
        }
        return ReportGenerator.instance;
    }
    async generateHtmlReport(results, options = {}) {
        const { title = 'Accessibility Report', includeAI = true, includeFixes = true, theme = 'light', outputPath } = options;
        // Group results by criterion
        const groupedResults = this.groupResultsByCriterion(results);
        // Generate HTML content
        const html = this.generateHtmlContent(title, groupedResults, {
            includeAI,
            includeFixes,
            theme
        });
        // Write to file if output path is provided
        if (outputPath) {
            await this.writeReportToFile(html, outputPath);
        }
        return html;
    }
    groupResultsByCriterion(results) {
        return results.reduce((acc, result) => {
            const criterion = result.criterion || 'Other';
            if (!acc[criterion]) {
                acc[criterion] = [];
            }
            acc[criterion].push(result);
            return acc;
        }, {});
    }
    generateHtmlContent(title, groupedResults, options) {
        const { includeAI, includeFixes, theme } = options;
        const themeStyles = this.getThemeStyles(theme);
        const issuesList = Object.entries(groupedResults)
            .map(([criterion, issues]) => this.generateCriterionSection(criterion, issues, options))
            .join('');
        const summary = this.generateSummary(groupedResults);
        return `
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>${title}</title>
          <style>
            ${themeStyles}
            ${this.getBaseStyles()}
          </style>
        </head>
        <body>
          <div class="container">
            <header>
              <h1>${title}</h1>
              <div class="summary">
                ${summary}
              </div>
            </header>
            <main>
              ${issuesList}
            </main>
            <footer>
              <p>Generated by Bluefly Accessibility Checker</p>
              <p>WCAG 2.2 AA Conformance</p>
            </footer>
          </div>
          <script>
            ${this.getInteractiveScripts()}
          </script>
        </body>
      </html>
    `;
    }
    generateCriterionSection(criterion, issues, options) {
        const { includeAI, includeFixes } = options;
        const issuesHtml = issues
            .map(issue => this.generateIssueCard(issue, { includeAI, includeFixes }))
            .join('');
        return `
      <section class="criterion-section" id="criterion-${criterion}">
        <h2>
          <span class="criterion-id">${criterion}</span>
          <span class="criterion-title">${this.getCriterionTitle(criterion)}</span>
        </h2>
        <div class="issues-list">
          ${issuesHtml}
        </div>
      </section>
    `;
    }
    generateIssueCard(issue, options) {
        const { includeAI, includeFixes } = options;
        const severityClass = `severity-${issue.severity}`;
        const aiSuggestions = includeAI && issue.aiSuggestions?.length
            ? `
        <div class="ai-suggestions">
          <h4>AI Suggestions</h4>
          <ul>
            ${issue.aiSuggestions.map(suggestion => `<li>${suggestion}</li>`).join('')}
          </ul>
        </div>
      `
            : '';
        const fixes = includeFixes && issue.fix
            ? `
        <div class="fix-suggestion">
          <h4>Suggested Fix</h4>
          <pre><code>${this.escapeHtml(issue.fix)}</code></pre>
        </div>
      `
            : '';
        return `
      <div class="issue-card ${severityClass}">
        <div class="issue-header">
          <span class="severity-badge">${issue.severity.toUpperCase()}</span>
          <h3>${this.escapeHtml(issue.message)}</h3>
        </div>
        <div class="issue-details">
          <p>${this.escapeHtml(issue.details || '')}</p>
          ${aiSuggestions}
          ${fixes}
          ${issue.code ? `<pre class="code-block"><code>${this.escapeHtml(issue.code)}</code></pre>` : ''}
        </div>
      </div>
    `;
    }
    generateSummary(groupedResults) {
        const totalIssues = Object.values(groupedResults).flat().length;
        const errorCount = Object.values(groupedResults)
            .flat()
            .filter(issue => issue.severity === 'error').length;
        const warningCount = Object.values(groupedResults)
            .flat()
            .filter(issue => issue.severity === 'warning').length;
        const infoCount = Object.values(groupedResults)
            .flat()
            .filter(issue => issue.severity === 'info').length;
        return `
      <div class="summary-grid">
        <div class="summary-item total">
          <span class="count">${totalIssues}</span>
          <span class="label">Total Issues</span>
        </div>
        <div class="summary-item errors">
          <span class="count">${errorCount}</span>
          <span class="label">Errors</span>
        </div>
        <div class="summary-item warnings">
          <span class="count">${warningCount}</span>
          <span class="label">Warnings</span>
        </div>
        <div class="summary-item info">
          <span class="count">${infoCount}</span>
          <span class="label">Info</span>
        </div>
      </div>
    `;
    }
    getThemeStyles(theme) {
        return theme === 'dark'
            ? `
        :root {
          --bg-color: #1a1a1a;
          --text-color: #ffffff;
          --card-bg: #2d2d2d;
          --border-color: #404040;
          --error-color: #ff6b6b;
          --warning-color: #ffd93d;
          --info-color: #4dabf7;
          --success-color: #51cf66;
        }
      `
            : `
        :root {
          --bg-color: #ffffff;
          --text-color: #1a1a1a;
          --card-bg: #f8f9fa;
          --border-color: #dee2e6;
          --error-color: #dc3545;
          --warning-color: #ffc107;
          --info-color: #0dcaf0;
          --success-color: #198754;
        }
      `;
    }
    getBaseStyles() {
        return `
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        line-height: 1.6;
        color: var(--text-color);
        background-color: var(--bg-color);
      }

      .container {
        max-width: 1200px;
        margin: 0 auto;
        padding: 2rem;
      }

      header {
        margin-bottom: 2rem;
      }

      h1 {
        font-size: 2rem;
        margin-bottom: 1rem;
      }

      .summary-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
        gap: 1rem;
        margin-bottom: 2rem;
      }

      .summary-item {
        padding: 1rem;
        border-radius: 0.5rem;
        background-color: var(--card-bg);
        text-align: center;
      }

      .summary-item .count {
        display: block;
        font-size: 2rem;
        font-weight: bold;
        margin-bottom: 0.5rem;
      }

      .criterion-section {
        margin-bottom: 2rem;
        padding: 1rem;
        border-radius: 0.5rem;
        background-color: var(--card-bg);
      }

      .issue-card {
        margin: 1rem 0;
        padding: 1rem;
        border-radius: 0.5rem;
        border: 1px solid var(--border-color);
        background-color: var(--card-bg);
      }

      .severity-badge {
        display: inline-block;
        padding: 0.25rem 0.5rem;
        border-radius: 0.25rem;
        font-size: 0.875rem;
        font-weight: bold;
        text-transform: uppercase;
      }

      .severity-error .severity-badge {
        background-color: var(--error-color);
        color: white;
      }

      .severity-warning .severity-badge {
        background-color: var(--warning-color);
        color: black;
      }

      .severity-info .severity-badge {
        background-color: var(--info-color);
        color: white;
      }

      .code-block {
        margin: 1rem 0;
        padding: 1rem;
        background-color: #2d2d2d;
        color: #ffffff;
        border-radius: 0.25rem;
        overflow-x: auto;
      }

      .ai-suggestions, .fix-suggestion {
        margin-top: 1rem;
        padding: 1rem;
        background-color: rgba(0, 0, 0, 0.05);
        border-radius: 0.25rem;
      }

      footer {
        margin-top: 2rem;
        padding-top: 1rem;
        border-top: 1px solid var(--border-color);
        text-align: center;
        color: #666;
      }
    `;
    }
    getInteractiveScripts() {
        return `
      document.addEventListener('DOMContentLoaded', () => {
        // Add copy button to code blocks
        document.querySelectorAll('.code-block').forEach(block => {
          const button = document.createElement('button');
          button.textContent = 'Copy';
          button.className = 'copy-button';
          button.onclick = () => {
            navigator.clipboard.writeText(block.textContent);
            button.textContent = 'Copied!';
            setTimeout(() => button.textContent = 'Copy', 2000);
          };
          block.parentNode.insertBefore(button, block);
        });

        // Add filter functionality
        const filterButtons = document.createElement('div');
        filterButtons.className = 'filter-buttons';
        filterButtons.innerHTML = \`
          <button data-severity="all">All</button>
          <button data-severity="error">Errors</button>
          <button data-severity="warning">Warnings</button>
          <button data-severity="info">Info</button>
        \`;
        document.querySelector('header').appendChild(filterButtons);

        filterButtons.addEventListener('click', (e) => {
          if (e.target.tagName === 'BUTTON') {
            const severity = e.target.dataset.severity;
            document.querySelectorAll('.issue-card').forEach(card => {
              if (severity === 'all' || card.classList.contains(\`severity-\${severity}\`)) {
                card.style.display = 'block';
              } else {
                card.style.display = 'none';
              }
            });
          }
        });
      });
    `;
    }
    getCriterionTitle(criterion) {
        // Map WCAG criteria to their titles
        const criterionTitles = {
            '1.1.1': 'Non-text Content',
            '1.4.3': 'Contrast (Minimum)',
            '2.1.1': 'Keyboard',
            '2.4.4': 'Link Purpose (In Context)',
            '4.1.2': 'Name, Role, Value',
            // Add more mappings as needed
        };
        return criterionTitles[criterion] || 'Unknown Criterion';
    }
    escapeHtml(unsafe) {
        return unsafe
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
    }
    async writeReportToFile(html, outputPath) {
        try {
            const dir = path_1.default.dirname(outputPath);
            await promises_1.default.mkdir(dir, { recursive: true });
            await promises_1.default.writeFile(outputPath, html, 'utf-8');
            logger_1.logger.info(`Report generated at ${outputPath}`);
        }
        catch (error) {
            logger_1.logger.error('Failed to write report:', error);
            throw new Error('Failed to write report to file');
        }
    }
}
exports.ReportGenerator = ReportGenerator;
//# sourceMappingURL=report-generator.js.map