import { Page } from 'playwright';

export interface AuditResult {
  category: string;
  score: number;
  issues: AuditIssue[];
  suggestions: string[];
}

export interface AuditIssue {
  severity: 'error' | 'warning' | 'info';
  message: string;
  element?: string;
  details?: any;
}

export class AuditEngine {
  async performAudit(page: Page, categories: string[] = ['all']): Promise<Record<string, AuditResult>> {
    const results: Record<string, AuditResult> = {};
    
    if (categories.includes('all') || categories.includes('accessibility')) {
      results.accessibility = await this.auditAccessibility(page);
    }
    
    if (categories.includes('all') || categories.includes('performance')) {
      results.performance = await this.auditPerformance(page);
    }
    
    if (categories.includes('all') || categories.includes('seo')) {
      results.seo = await this.auditSEO(page);
    }
    
    if (categories.includes('all') || categories.includes('bestPractices')) {
      results.bestPractices = await this.auditBestPractices(page);
    }
    
    if (categories.includes('all') || categories.includes('security')) {
      results.security = await this.auditSecurity(page);
    }
    
    return results;
  }
  
  private async auditAccessibility(page: Page): Promise<AuditResult> {
    const issues: AuditIssue[] = [];
    const suggestions: string[] = [];
    
    const audit = await page.evaluate(() => {
      const results = {
        imagesWithoutAlt: 0,
        buttonsWithoutText: 0,
        inputsWithoutLabels: 0,
        lowContrastElements: 0,
        missingLandmarks: false,
        formIssues: 0,
      };
      
      // Check images without alt text
      document.querySelectorAll('img:not([alt])').forEach((img) => {
        results.imagesWithoutAlt++;
      });
      
      // Check buttons without accessible text
      document.querySelectorAll('button').forEach((button) => {
        if (!button.textContent?.trim() && !button.getAttribute('aria-label')) {
          results.buttonsWithoutText++;
        }
      });
      
      // Check inputs without labels
      document.querySelectorAll('input:not([type="hidden"])').forEach((input) => {
        const id = input.id;
        if (!id || !document.querySelector(`label[for="${id}"]`)) {
          if (!input.getAttribute('aria-label')) {
            results.inputsWithoutLabels++;
          }
        }
      });
      
      // Check for main landmark
      if (!document.querySelector('main, [role="main"]')) {
        results.missingLandmarks = true;
      }
      
      // Check form accessibility
      document.querySelectorAll('form').forEach((form) => {
        if (!form.querySelector('button[type="submit"], input[type="submit"]')) {
          results.formIssues++;
        }
      });
      
      return results;
    });
    
    // Calculate score (0-100)
    let score = 100;
    
    if (audit.imagesWithoutAlt > 0) {
      score -= Math.min(20, audit.imagesWithoutAlt * 5);
      issues.push({
        severity: 'error',
        message: `${audit.imagesWithoutAlt} images missing alt text`,
        details: { count: audit.imagesWithoutAlt }
      });
      suggestions.push('Add descriptive alt text to all images');
    }
    
    if (audit.buttonsWithoutText > 0) {
      score -= Math.min(15, audit.buttonsWithoutText * 5);
      issues.push({
        severity: 'error',
        message: `${audit.buttonsWithoutText} buttons without accessible text`,
        details: { count: audit.buttonsWithoutText }
      });
      suggestions.push('Add text content or aria-label to buttons');
    }
    
    if (audit.inputsWithoutLabels > 0) {
      score -= Math.min(15, audit.inputsWithoutLabels * 3);
      issues.push({
        severity: 'error',
        message: `${audit.inputsWithoutLabels} form inputs without labels`,
        details: { count: audit.inputsWithoutLabels }
      });
      suggestions.push('Associate labels with form inputs using "for" attribute');
    }
    
    if (audit.missingLandmarks) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: 'Missing main landmark',
        details: { landmark: 'main' }
      });
      suggestions.push('Add <main> element or role="main" to primary content');
    }
    
    return {
      category: 'accessibility',
      score: Math.max(0, score),
      issues,
      suggestions
    };
  }
  
  private async auditPerformance(page: Page): Promise<AuditResult> {
    const issues: AuditIssue[] = [];
    const suggestions: string[] = [];
    
    // Get performance metrics
    const metrics = await page.evaluate(() => {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      const paint = performance.getEntriesByType('paint');
      
      return {
        domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
        loadTime: navigation.loadEventEnd - navigation.loadEventStart,
        firstPaint: paint.find(p => p.name === 'first-paint')?.startTime || 0,
        firstContentfulPaint: paint.find(p => p.name === 'first-contentful-paint')?.startTime || 0,
        resources: performance.getEntriesByType('resource').length,
        totalSize: performance.getEntriesByType('resource').reduce((acc, r: any) => acc + (r.transferSize || 0), 0),
        largeImages: Array.from(document.querySelectorAll('img')).filter((img) => {
          return img.naturalWidth > 1920 || img.naturalHeight > 1080;
        }).length,
        scripts: document.querySelectorAll('script').length,
        stylesheets: document.querySelectorAll('link[rel="stylesheet"]').length,
      };
    });
    
    // Calculate score
    let score = 100;
    
    // Check load time
    if (metrics.loadTime > 3000) {
      score -= 20;
      issues.push({
        severity: 'warning',
        message: `Page load time is ${(metrics.loadTime / 1000).toFixed(2)}s (target: <3s)`,
        details: { loadTime: metrics.loadTime }
      });
      suggestions.push('Optimize resource loading and reduce page weight');
    }
    
    // Check FCP
    if (metrics.firstContentfulPaint > 1800) {
      score -= 15;
      issues.push({
        severity: 'warning',
        message: `First Contentful Paint is ${(metrics.firstContentfulPaint / 1000).toFixed(2)}s (target: <1.8s)`,
        details: { fcp: metrics.firstContentfulPaint }
      });
      suggestions.push('Reduce render-blocking resources');
    }
    
    // Check resource count
    if (metrics.resources > 50) {
      score -= 10;
      issues.push({
        severity: 'info',
        message: `Loading ${metrics.resources} resources (consider bundling)`,
        details: { resourceCount: metrics.resources }
      });
      suggestions.push('Bundle and minify resources');
    }
    
    // Check for large images
    if (metrics.largeImages > 0) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: `${metrics.largeImages} oversized images detected`,
        details: { largeImages: metrics.largeImages }
      });
      suggestions.push('Optimize images - use appropriate sizes and formats (WebP, AVIF)');
    }
    
    // Check total size
    const totalSizeMB = metrics.totalSize / (1024 * 1024);
    if (totalSizeMB > 5) {
      score -= 15;
      issues.push({
        severity: 'warning',
        message: `Total page size is ${totalSizeMB.toFixed(2)}MB (target: <5MB)`,
        details: { totalSize: metrics.totalSize }
      });
      suggestions.push('Reduce page weight through compression and optimization');
    }
    
    return {
      category: 'performance',
      score: Math.max(0, score),
      issues,
      suggestions
    };
  }
  
  private async auditSEO(page: Page): Promise<AuditResult> {
    const issues: AuditIssue[] = [];
    const suggestions: string[] = [];
    
    const seoData = await page.evaluate(() => {
      const title = document.querySelector('title')?.textContent || '';
      const metaDescription = document.querySelector('meta[name="description"]')?.getAttribute('content') || '';
      const h1Count = document.querySelectorAll('h1').length;
      const canonicalLink = document.querySelector('link[rel="canonical"]')?.getAttribute('href');
      const viewport = document.querySelector('meta[name="viewport"]')?.getAttribute('content');
      const ogTags = {
        title: document.querySelector('meta[property="og:title"]')?.getAttribute('content'),
        description: document.querySelector('meta[property="og:description"]')?.getAttribute('content'),
        image: document.querySelector('meta[property="og:image"]')?.getAttribute('content'),
      };
      
      return {
        title,
        titleLength: title.length,
        metaDescription,
        descriptionLength: metaDescription.length,
        h1Count,
        hasCanonical: !!canonicalLink,
        hasViewport: !!viewport,
        hasOgTags: !!(ogTags.title && ogTags.description),
        hasRobotsTxt: false, // Would need server check
      };
    });
    
    let score = 100;
    
    // Check title
    if (!seoData.title) {
      score -= 20;
      issues.push({
        severity: 'error',
        message: 'Missing page title',
        details: { field: 'title' }
      });
      suggestions.push('Add a descriptive <title> tag');
    } else if (seoData.titleLength < 30 || seoData.titleLength > 60) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: `Title length is ${seoData.titleLength} characters (ideal: 30-60)`,
        details: { titleLength: seoData.titleLength }
      });
      suggestions.push('Optimize title length for search results');
    }
    
    // Check meta description
    if (!seoData.metaDescription) {
      score -= 15;
      issues.push({
        severity: 'error',
        message: 'Missing meta description',
        details: { field: 'description' }
      });
      suggestions.push('Add a compelling meta description');
    } else if (seoData.descriptionLength < 120 || seoData.descriptionLength > 160) {
      score -= 5;
      issues.push({
        severity: 'warning',
        message: `Meta description length is ${seoData.descriptionLength} characters (ideal: 120-160)`,
        details: { descriptionLength: seoData.descriptionLength }
      });
    }
    
    // Check H1
    if (seoData.h1Count === 0) {
      score -= 15;
      issues.push({
        severity: 'error',
        message: 'No H1 tag found',
        details: { h1Count: 0 }
      });
      suggestions.push('Add a single H1 tag with primary keyword');
    } else if (seoData.h1Count > 1) {
      score -= 5;
      issues.push({
        severity: 'warning',
        message: `Multiple H1 tags found (${seoData.h1Count})`,
        details: { h1Count: seoData.h1Count }
      });
      suggestions.push('Use only one H1 tag per page');
    }
    
    // Check mobile viewport
    if (!seoData.hasViewport) {
      score -= 15;
      issues.push({
        severity: 'error',
        message: 'Missing viewport meta tag',
        details: { field: 'viewport' }
      });
      suggestions.push('Add <meta name="viewport" content="width=device-width, initial-scale=1">');
    }
    
    // Check Open Graph
    if (!seoData.hasOgTags) {
      score -= 5;
      issues.push({
        severity: 'info',
        message: 'Missing Open Graph tags for social sharing',
        details: { field: 'og:tags' }
      });
      suggestions.push('Add Open Graph meta tags for better social media sharing');
    }
    
    return {
      category: 'seo',
      score: Math.max(0, score),
      issues,
      suggestions
    };
  }
  
  private async auditBestPractices(page: Page): Promise<AuditResult> {
    const issues: AuditIssue[] = [];
    const suggestions: string[] = [];
    
    const practices = await page.evaluate(() => {
      const hasHttps = window.location.protocol === 'https:';
      const hasLang = !!document.documentElement.getAttribute('lang');
      const hasCharset = !!document.querySelector('meta[charset]');
      const consoleErrors = (window as any).__AI_DEBUG__?.events?.filter((e: any) => e.type === 'console.error').length || 0;
      const hasFavicon = !!document.querySelector('link[rel="icon"], link[rel="shortcut icon"]');
      
      // Check for common bad practices
      const inlineStyles = document.querySelectorAll('[style]').length;
      const inlineScripts = document.querySelectorAll('script:not([src])').length;
      
      return {
        hasHttps,
        hasLang,
        hasCharset,
        consoleErrors,
        hasFavicon,
        inlineStyles,
        inlineScripts,
      };
    });
    
    let score = 100;
    
    if (!practices.hasLang) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: 'Missing lang attribute on html element',
        details: { field: 'lang' }
      });
      suggestions.push('Add lang attribute to <html> element');
    }
    
    if (!practices.hasCharset) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: 'Missing charset meta tag',
        details: { field: 'charset' }
      });
      suggestions.push('Add <meta charset="UTF-8">');
    }
    
    if (practices.consoleErrors > 0) {
      score -= Math.min(20, practices.consoleErrors * 5);
      issues.push({
        severity: 'error',
        message: `${practices.consoleErrors} console errors detected`,
        details: { errorCount: practices.consoleErrors }
      });
      suggestions.push('Fix JavaScript errors in console');
    }
    
    if (!practices.hasFavicon) {
      score -= 5;
      issues.push({
        severity: 'info',
        message: 'Missing favicon',
        details: { field: 'favicon' }
      });
      suggestions.push('Add a favicon for better branding');
    }
    
    if (practices.inlineStyles > 10) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: `${practices.inlineStyles} inline styles found`,
        details: { inlineStyles: practices.inlineStyles }
      });
      suggestions.push('Move inline styles to CSS files');
    }
    
    if (practices.inlineScripts > 2) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: `${practices.inlineScripts} inline scripts found`,
        details: { inlineScripts: practices.inlineScripts }
      });
      suggestions.push('Move inline scripts to external files');
    }
    
    return {
      category: 'bestPractices',
      score: Math.max(0, score),
      issues,
      suggestions
    };
  }
  
  private async auditSecurity(page: Page): Promise<AuditResult> {
    const issues: AuditIssue[] = [];
    const suggestions: string[] = [];
    
    const security = await page.evaluate(() => {
      const forms = document.querySelectorAll('form');
      const passwordInputs = document.querySelectorAll('input[type="password"]');
      const httpLinks = Array.from(document.querySelectorAll('a[href^="http://"]')).length;
      const externalScripts = Array.from(document.querySelectorAll('script[src]'))
        .filter(s => {
          const src = s.getAttribute('src') || '';
          return src.startsWith('http') && !src.includes(window.location.hostname);
        }).length;
      
      // Check for sensitive data in URLs
      const urlParams = new URLSearchParams(window.location.search);
      const sensitiveParams = ['password', 'token', 'key', 'secret', 'auth'].filter(
        param => urlParams.has(param)
      );
      
      return {
        formCount: forms.length,
        httpsFormActions: Array.from(forms).filter(f => {
          const action = f.getAttribute('action') || '';
          return !action || action.startsWith('https://') || action.startsWith('/');
        }).length,
        passwordInputs: passwordInputs.length,
        autocompleteOffPasswords: Array.from(passwordInputs).filter(
          p => p.getAttribute('autocomplete') === 'off' || p.getAttribute('autocomplete') === 'new-password'
        ).length,
        httpLinks,
        externalScripts,
        sensitiveParams,
      };
    });
    
    let score = 100;
    
    // Check forms use HTTPS
    if (security.formCount > security.httpsFormActions) {
      score -= 20;
      issues.push({
        severity: 'error',
        message: 'Forms submitting over insecure HTTP',
        details: { insecureForms: security.formCount - security.httpsFormActions }
      });
      suggestions.push('Ensure all forms submit over HTTPS');
    }
    
    // Check password autocomplete
    if (security.passwordInputs > security.autocompleteOffPasswords) {
      score -= 10;
      issues.push({
        severity: 'warning',
        message: 'Password fields allow autocomplete',
        details: { count: security.passwordInputs - security.autocompleteOffPasswords }
      });
      suggestions.push('Set autocomplete="new-password" on password fields');
    }
    
    // Check for HTTP links
    if (security.httpLinks > 0) {
      score -= 15;
      issues.push({
        severity: 'warning',
        message: `${security.httpLinks} links use insecure HTTP`,
        details: { httpLinks: security.httpLinks }
      });
      suggestions.push('Update all links to use HTTPS');
    }
    
    // Check external scripts
    if (security.externalScripts > 5) {
      score -= 10;
      issues.push({
        severity: 'info',
        message: `${security.externalScripts} external scripts loaded`,
        details: { externalScripts: security.externalScripts }
      });
      suggestions.push('Audit external scripts and consider using Subresource Integrity (SRI)');
    }
    
    // Check for sensitive data in URL
    if (security.sensitiveParams.length > 0) {
      score -= 25;
      issues.push({
        severity: 'error',
        message: `Sensitive data in URL parameters: ${security.sensitiveParams.join(', ')}`,
        details: { params: security.sensitiveParams }
      });
      suggestions.push('Never pass sensitive data in URL parameters');
    }
    
    return {
      category: 'security',
      score: Math.max(0, score),
      issues,
      suggestions
    };
  }
}