import { Page } from 'playwright';

export interface TurboEvent {
  type: 'visit' | 'cache-miss' | 'frame-load' | 'stream';
  target: string;
  timing: number;
  timestamp: Date;
}

export interface StimulusController {
  identifier: string;
  element: string;
  actions: string[];
  targets: string[];
  connected: boolean;
}

export interface CSRFIssue {
  endpoint: string;
  method: string;
  hasToken: boolean;
  tokenName: string;
  timestamp: Date;
}

export interface LiveReloadEvent {
  type: 'css' | 'js' | 'html' | 'partial';
  file: string;
  timestamp: Date;
  reloadTime: number;
}

export class ServerFrameworkDebugEngine {
  private page?: Page;
  private turboEvents: TurboEvent[] = [];
  private csrfIssues: CSRFIssue[] = [];
  private liveReloadEvents: LiveReloadEvent[] = [];
  
  async attachToPage(page: Page): Promise<void> {
    this.page = page;
    
    await this.injectServerFrameworkMonitoring();
    await this.setupCSRFTracking();
    await this.setupFormTracking();
  }
  
  async detectServerFramework(page: Page): Promise<'rails' | 'django' | null> {
    const detection = await page.evaluate(() => {
      // Rails detection
      const hasRailsUJS = !!(window as any).Rails;
      const hasTurbo = !!(window as any).Turbo;
      const hasActionCable = !!(window as any).ActionCable;
      const railsMeta = document.querySelector('meta[name="csrf-token"]');
      const railsData = document.querySelector('[data-rails-form]') || 
                       document.querySelector('[data-remote="true"]');
      
      // Django detection  
      const djangoCSRF = document.querySelector('input[name="csrfmiddlewaretoken"]');
      const djangoAdmin = document.querySelector('.django-admin-container');
      const djangoDebugToolbar = document.getElementById('djDebug');
      const djangoMessages = document.querySelector('.django-messages');
      
      if (hasRailsUJS || hasTurbo || hasActionCable || railsMeta || railsData) {
        return 'rails';
      }
      
      if (djangoCSRF || djangoAdmin || djangoDebugToolbar || djangoMessages) {
        return 'django';
      }
      
      return null;
    });
    
    return detection;
  }
  
  private async injectServerFrameworkMonitoring(): Promise<void> {
    if (!this.page) return;
    
    await this.page.addInitScript(() => {
      (window as any).__SERVER_FRAMEWORK_DEBUG__ = {
        turboEvents: [],
        stimulusControllers: [],
        formSubmissions: [],
        ajaxRequests: [],
        
        init: function() {
          // Monitor Turbo (Rails)
          if ((window as any).Turbo) {
            this.monitorTurbo();
          }
          
          // Monitor Stimulus
          if ((window as any).Stimulus) {
            this.monitorStimulus();
          }
          
          // Monitor Rails UJS
          if ((window as any).Rails) {
            this.monitorRailsUJS();
          }
          
          // Monitor Django forms
          this.monitorForms();
          
          // Monitor AJAX/Fetch
          this.monitorAjax();
        },
        
        monitorTurbo: function() {
          const debug = this;
          
          document.addEventListener('turbo:visit', (event: any) => {
            debug.turboEvents.push({
              type: 'visit',
              target: event.detail.url,
              timing: Date.now(),
              timestamp: new Date().toISOString()
            });
          });
          
          document.addEventListener('turbo:cache-miss', (event: any) => {
            debug.turboEvents.push({
              type: 'cache-miss',
              target: window.location.href,
              timing: Date.now(),
              timestamp: new Date().toISOString()
            });
          });
          
          document.addEventListener('turbo:frame-load', (event: any) => {
            debug.turboEvents.push({
              type: 'frame-load',
              target: event.target.id,
              timing: Date.now(),
              timestamp: new Date().toISOString()
            });
          });
          
          document.addEventListener('turbo:submit-start', (event: any) => {
            const form = event.target;
            debug.formSubmissions.push({
              action: form.action,
              method: form.method,
              turbo: true,
              hasFile: form.querySelector('input[type="file"]') !== null,
              timestamp: new Date().toISOString()
            });
          });
        },
        
        monitorStimulus: function() {
          const debug = this;
          
          // Try to access Stimulus application
          const app = (window as any).Stimulus;
          if (!app) return;
          
          // Monitor controller connections
          const originalRegister = app.register;
          app.register = function(identifier: string, controller: any) {
            debug.stimulusControllers.push({
              identifier,
              controller: controller.name,
              timestamp: new Date().toISOString()
            });
            return originalRegister.call(this, identifier, controller);
          };
        },
        
        monitorRailsUJS: function() {
          const debug = this;
          
          document.addEventListener('ajax:send', (event: any) => {
            debug.ajaxRequests.push({
              url: event.detail[0].url,
              method: event.detail[0].type,
              rails: true,
              timestamp: new Date().toISOString()
            });
          });
          
          document.addEventListener('ajax:error', (event: any) => {
            const lastRequest = debug.ajaxRequests[debug.ajaxRequests.length - 1];
            if (lastRequest) {
              lastRequest.error = true;
              lastRequest.status = event.detail[2].status;
            }
          });
        },
        
        monitorForms: function() {
          const debug = this;
          
          document.addEventListener('submit', (event: any) => {
            const form = event.target;
            if (form.tagName !== 'FORM') return;
            
            // Check for CSRF token
            const railsToken = form.querySelector('input[name="authenticity_token"]');
            const djangoToken = form.querySelector('input[name="csrfmiddlewaretoken"]');
            
            debug.formSubmissions.push({
              action: form.action,
              method: form.method,
              hasCSRF: !!(railsToken || djangoToken),
              csrfField: railsToken ? 'authenticity_token' : djangoToken ? 'csrfmiddlewaretoken' : null,
              hasFile: form.querySelector('input[type="file"]') !== null,
              timestamp: new Date().toISOString()
            });
          });
        },
        
        monitorAjax: function() {
          const debug = this;
          
          // Monitor fetch
          const originalFetch = window.fetch;
          window.fetch = async function(...args) {
            const url = typeof args[0] === 'string' ? args[0] : (args[0] as Request).url;
            const options = args[1] || {};
            
            const request: any = {
              url,
              method: options.method || 'GET',
              hasCSRF: false,
              timestamp: new Date().toISOString()
            };
            
            // Check for CSRF in headers
            if (options.headers) {
              const headers = options.headers as Record<string, string>;
              request.hasCSRF = !!(headers['X-CSRF-Token'] || headers['X-CSRFToken']);
            }
            
            debug.ajaxRequests.push(request);
            
            try {
              const response = await originalFetch.apply(this, args);
              request.status = response.status;
              return response;
            } catch (error) {
              request.error = true;
              throw error;
            }
          };
        }
      };
      
      // Initialize after DOM ready
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
          (window as any).__SERVER_FRAMEWORK_DEBUG__.init();
        });
      } else {
        (window as any).__SERVER_FRAMEWORK_DEBUG__.init();
      }
    });
  }
  
  private async setupCSRFTracking(): Promise<void> {
    if (!this.page) return;
    
    // Monitor network requests for CSRF issues
    this.page.on('response', async (response) => {
      const request = response.request();
      const method = request.method();
      
      // Only check state-changing methods
      if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) {
        const headers = request.headers();
        const url = request.url();
        
        // Check for CSRF tokens
        const hasCSRFHeader = !!(
          headers['x-csrf-token'] || 
          headers['x-csrftoken'] || 
          headers['x-xsrf-token'] ||
          headers['x-requested-with'] === 'XMLHttpRequest'
        );
        
        // Check response for CSRF errors
        if (response.status() === 403) {
          const text = await response.text().catch(() => '');
          if (text.includes('CSRF') || text.includes('csrf')) {
            this.csrfIssues.push({
              endpoint: url,
              method,
              hasToken: hasCSRFHeader,
              tokenName: 'Unknown',
              timestamp: new Date()
            });
          }
        }
      }
    });
  }
  
  private async setupFormTracking(): Promise<void> {
    if (!this.page) return;
    
    // Track form submissions for multipart issues
    await this.page.addInitScript(() => {
      const originalSubmit = HTMLFormElement.prototype.submit;
      HTMLFormElement.prototype.submit = function() {
        const hasFile = this.querySelector('input[type="file"]') !== null;
        const enctype = this.getAttribute('enctype');
        
        if (hasFile && enctype !== 'multipart/form-data') {
          console.error('Form with file input missing multipart/form-data enctype');
        }
        
        return originalSubmit.call(this);
      };
    });
  }
  
  async getTurboEvents(): Promise<TurboEvent[]> {
    if (!this.page) return [];
    
    const events = await this.page.evaluate(() => {
      return (window as any).__SERVER_FRAMEWORK_DEBUG__?.turboEvents || [];
    });
    
    return events.map((e: any) => ({
      ...e,
      timestamp: new Date(e.timestamp)
    }));
  }
  
  async getStimulusControllers(): Promise<StimulusController[]> {
    if (!this.page) return [];
    
    return await this.page.evaluate(() => {
      const controllers: StimulusController[] = [];
      
      // Find all Stimulus controlled elements
      document.querySelectorAll('[data-controller]').forEach((element) => {
        const identifier = element.getAttribute('data-controller') || '';
        
        // Extract actions
        const actionAttr = element.getAttribute('data-action') || '';
        const actions = actionAttr.split(' ').filter(a => a.length > 0);
        
        // Extract targets
        const targets: string[] = [];
        Array.from(element.attributes).forEach(attr => {
          if (attr.name.startsWith('data-') && attr.name.endsWith('-target')) {
            targets.push(attr.value);
          }
        });
        
        controllers.push({
          identifier,
          element: element.tagName + (element.id ? `#${element.id}` : ''),
          actions,
          targets,
          connected: true // Assume connected if found in DOM
        });
      });
      
      return controllers;
    });
  }
  
  async getFormSubmissions(): Promise<any[]> {
    if (!this.page) return [];
    
    return await this.page.evaluate(() => {
      return (window as any).__SERVER_FRAMEWORK_DEBUG__?.formSubmissions || [];
    });
  }
  
  async getCSRFIssues(): Promise<CSRFIssue[]> {
    return this.csrfIssues;
  }
  
  async detectServerFrameworkProblems(): Promise<Array<{
    problem: string;
    severity: 'low' | 'medium' | 'high';
    description: string;
    solution: string;
  }>> {
    const problems = [];
    const framework = await this.detectServerFramework(this.page!);
    
    // CSRF Issues
    const csrfIssues = await this.getCSRFIssues();
    if (csrfIssues.length > 0) {
      problems.push({
        problem: 'CSRF Token Issues',
        severity: 'high' as const,
        description: `${csrfIssues.length} requests failed or missing CSRF tokens.`,
        solution: framework === 'rails' 
          ? 'Ensure <%= csrf_meta_tags %> in layout and use Rails UJS or include token in AJAX headers.'
          : 'Include {% csrf_token %} in forms and add token to AJAX requests.'
      });
    }
    
    // Form Issues
    const forms = await this.getFormSubmissions();
    const formsWithoutCSRF = forms.filter(f => !f.hasCSRF && f.method.toUpperCase() !== 'GET');
    if (formsWithoutCSRF.length > 0) {
      problems.push({
        problem: 'Forms Missing CSRF Protection',
        severity: 'high' as const,
        description: `${formsWithoutCSRF.length} forms lack CSRF tokens.`,
        solution: framework === 'rails'
          ? 'Add <%= form_with %> or <%= form_tag %> helpers which include CSRF automatically.'
          : 'Ensure {% csrf_token %} is inside all Django forms.'
      });
    }
    
    // Multipart form issues
    const fileFormsWithoutMultipart = forms.filter(f => 
      f.hasFile && f.enctype !== 'multipart/form-data'
    );
    if (fileFormsWithoutMultipart.length > 0) {
      problems.push({
        problem: 'File Upload Forms Misconfigured',
        severity: 'high' as const,
        description: `${fileFormsWithoutMultipart.length} file upload forms missing multipart encoding.`,
        solution: 'Add enctype="multipart/form-data" to forms with file inputs.'
      });
    }
    
    // Turbo/Hotwire Issues (Rails)
    if (framework === 'rails') {
      const turboEvents = await this.getTurboEvents();
      const cacheMisses = turboEvents.filter(e => e.type === 'cache-miss');
      
      if (cacheMisses.length > turboEvents.filter(e => e.type === 'visit').length * 0.5) {
        problems.push({
          problem: 'Poor Turbo Cache Hit Rate',
          severity: 'low' as const,
          description: `Over 50% of Turbo visits are cache misses, reducing navigation speed.`,
          solution: 'Ensure Turbo cache is enabled and pages are cacheable. Avoid dynamic content in cached pages.'
        });
      }
      
      // Check for Stimulus issues
      const controllers = await this.getStimulusControllers();
      const duplicateControllers = controllers.filter((c, i) => 
        controllers.findIndex(c2 => c2.identifier === c.identifier) !== i
      );
      
      if (duplicateControllers.length > 0) {
        problems.push({
          problem: 'Duplicate Stimulus Controllers',
          severity: 'medium' as const,
          description: `Found duplicate controller registrations which may cause conflicts.`,
          solution: 'Ensure each Stimulus controller is registered only once.'
        });
      }
    }
    
    // AJAX without CSRF
    const ajaxRequests = await this.page!.evaluate(() => 
      (window as any).__SERVER_FRAMEWORK_DEBUG__?.ajaxRequests || []
    );
    const unsafeAjax = ajaxRequests.filter((r: any) => 
      ['POST', 'PUT', 'PATCH', 'DELETE'].includes(r.method.toUpperCase()) && !r.hasCSRF
    );
    
    if (unsafeAjax.length > 0) {
      problems.push({
        problem: 'AJAX Requests Missing CSRF',
        severity: 'high' as const,
        description: `${unsafeAjax.length} state-changing AJAX requests lack CSRF tokens.`,
        solution: framework === 'rails'
          ? 'Use Rails.ajax() or add X-CSRF-Token header from meta tag.'
          : 'Add X-CSRFToken header from cookie or hidden input.'
      });
    }
    
    return problems;
  }
  
  async getLiveReloadStats(): Promise<{
    events: LiveReloadEvent[];
    avgReloadTime: number;
    fileTypes: Record<string, number>;
  }> {
    const events = this.liveReloadEvents;
    const avgReloadTime = events.length > 0
      ? events.reduce((sum, e) => sum + e.reloadTime, 0) / events.length
      : 0;
    
    const fileTypes: Record<string, number> = {};
    events.forEach(e => {
      fileTypes[e.type] = (fileTypes[e.type] || 0) + 1;
    });
    
    return { events, avgReloadTime, fileTypes };
  }
}