import { Page } from 'playwright';
import WebSocket from 'ws';

export interface FlutterWidget {
  id: string;
  type: string;
  properties: Record<string, any>;
  children: FlutterWidget[];
  renderObject?: {
    type: string;
    size?: { width: number; height: number };
    position?: { x: number; y: number };
  };
}

export interface FlutterState {
  widgets: FlutterWidget[];
  performance: {
    fps: number;
    frameTime: number;
    widgetBuildTime: number;
    rasterTime: number;
  };
  memory: {
    used: number;
    capacity: number;
  };
}

export class FlutterDebugEngine {
  private ws?: WebSocket;
  private debugPort?: number;
  private vmServiceUrl?: string;
  private isConnected: boolean = false;
  
  async detectFlutterWeb(page: Page): Promise<boolean> {
    return await page.evaluate(() => {
      // Check for Flutter-specific globals and elements
      const hasFlutterGlobals = !!(window as any).flutterConfiguration || 
                               !!(window as any).$flutterDriver;
      const hasFlutterElements = document.querySelector('flt-scene-host') !== null ||
                                document.querySelector('flt-glass-pane') !== null ||
                                document.querySelector('flutter-view') !== null;
      
      // Check for Flutter-specific scripts
      const scripts = Array.from(document.querySelectorAll('script'));
      const hasFlutterScripts = scripts.some(script => 
        script.src.includes('flutter.js') || 
        script.src.includes('flutter_web')
      );
      
      return hasFlutterGlobals || hasFlutterElements || hasFlutterScripts;
    });
  }
  
  async findDebugPort(page: Page): Promise<number | null> {
    // Try to find Flutter DevTools port from console logs
    const logs = await page.evaluate(() => {
      return (window as any).__consoleHistory || [];
    });
    
    // Look for Observatory/DevTools URL in logs
    const portMatch = logs.find((log: string) => 
      log.includes('Observatory listening on') ||
      log.includes('DevTools listening on')
    );
    
    if (portMatch) {
      const match = portMatch.match(/:(\d+)/);
      if (match) {
        return parseInt(match[1]);
      }
    }
    
    // Try common Flutter debug ports
    const commonPorts = [9100, 9101, 9102, 9200, 9201];
    for (const port of commonPorts) {
      if (await this.checkPort(port)) {
        return port;
      }
    }
    
    return null;
  }
  
  private async checkPort(port: number): Promise<boolean> {
    try {
      const response = await fetch(`http://localhost:${port}/ws`);
      return response.ok;
    } catch {
      return false;
    }
  }
  
  async connect(port: number): Promise<boolean> {
    if (this.isConnected) {
      return true;
    }
    
    try {
      this.debugPort = port;
      this.vmServiceUrl = `ws://localhost:${port}/ws`;
      
      return new Promise((resolve) => {
        this.ws = new WebSocket(this.vmServiceUrl!);
        
        this.ws.on('open', () => {
          this.isConnected = true;
          console.log('Connected to Flutter DevTools');
          resolve(true);
        });
        
        this.ws.on('error', (error) => {
          console.error('Flutter DevTools connection error:', error);
          resolve(false);
        });
        
        this.ws.on('message', (data) => {
          this.handleMessage(data.toString());
        });
      });
    } catch (error) {
      console.error('Failed to connect to Flutter DevTools:', error);
      return false;
    }
  }
  
  private handleMessage(message: string) {
    try {
      const data = JSON.parse(message);
      // Handle VM service protocol messages
      if (data.method === 'streamNotify') {
        this.handleStreamNotification(data.params);
      }
    } catch (error) {
      console.error('Error parsing Flutter message:', error);
    }
  }
  
  private handleStreamNotification(params: any) {
    // Handle different stream types
    switch (params.streamId) {
      case 'Extension':
        // Flutter extension events
        break;
      case 'Timeline':
        // Performance timeline events
        break;
      case 'Debug':
        // Debug events
        break;
    }
  }
  
  async getWidgetTree(): Promise<FlutterWidget | null> {
    if (!this.isConnected || !this.ws) {
      return null;
    }
    
    // Send request for widget tree
    const request = {
      id: Date.now().toString(),
      method: 'ext.flutter.inspector.getWidgetTree',
      params: {}
    };
    
    return new Promise((resolve) => {
      const timeout = setTimeout(() => resolve(null), 5000);
      
      const handler = (data: WebSocket.Data) => {
        try {
          const response = JSON.parse(data.toString());
          if (response.id === request.id) {
            clearTimeout(timeout);
            this.ws!.off('message', handler);
            resolve(this.parseWidgetTree(response.result));
          }
        } catch (error) {
          console.error('Error parsing widget tree response:', error);
        }
      };
      
      this.ws!.on('message', handler);
      this.ws!.send(JSON.stringify(request));
    });
  }
  
  private parseWidgetTree(data: any): FlutterWidget {
    return {
      id: data.id || 'root',
      type: data.description?.split('(')[0] || 'Unknown',
      properties: data.properties || {},
      children: (data.children || []).map((child: any) => this.parseWidgetTree(child)),
      renderObject: data.renderObject ? {
        type: data.renderObject.description,
        size: data.renderObject.size,
        position: data.renderObject.position
      } : undefined
    };
  }
  
  async getPerformanceInfo(): Promise<any> {
    if (!this.isConnected || !this.ws) {
      return null;
    }
    
    const request = {
      id: Date.now().toString(),
      method: 'ext.flutter.getVMTimeline',
      params: {
        timeOriginMicros: Date.now() * 1000 - 5000000, // Last 5 seconds
        timeExtentMicros: 5000000
      }
    };
    
    return new Promise((resolve) => {
      const timeout = setTimeout(() => resolve(null), 3000);
      
      const handler = (data: WebSocket.Data) => {
        try {
          const response = JSON.parse(data.toString());
          if (response.id === request.id) {
            clearTimeout(timeout);
            this.ws!.off('message', handler);
            resolve(this.parsePerformanceData(response.result));
          }
        } catch (error) {
          console.error('Error parsing performance data:', error);
        }
      };
      
      this.ws!.on('message', handler);
      this.ws!.send(JSON.stringify(request));
    });
  }
  
  private parsePerformanceData(data: any): any {
    const events = data.traceEvents || [];
    
    // Calculate FPS from frame events
    const frameEvents = events.filter((e: any) => e.name === 'Frame');
    const fps = frameEvents.length > 0 
      ? Math.round(1000000 / (frameEvents[frameEvents.length - 1].ts - frameEvents[0].ts) * frameEvents.length)
      : 0;
    
    // Calculate average frame times
    const buildTimes = events
      .filter((e: any) => e.name === 'Build')
      .map((e: any) => e.dur || 0);
    const avgBuildTime = buildTimes.length > 0
      ? buildTimes.reduce((a: number, b: number) => a + b, 0) / buildTimes.length / 1000
      : 0;
    
    return {
      fps,
      frameTime: fps > 0 ? 1000 / fps : 0,
      widgetBuildTime: avgBuildTime,
      rasterTime: 0, // Would need raster thread events
      eventCount: events.length
    };
  }
  
  async inspectWidget(widgetId: string): Promise<any> {
    if (!this.isConnected || !this.ws) {
      return null;
    }
    
    const request = {
      id: Date.now().toString(),
      method: 'ext.flutter.inspector.getProperties',
      params: {
        objectId: widgetId,
        depth: 2
      }
    };
    
    return new Promise((resolve) => {
      const timeout = setTimeout(() => resolve(null), 3000);
      
      const handler = (data: WebSocket.Data) => {
        try {
          const response = JSON.parse(data.toString());
          if (response.id === request.id) {
            clearTimeout(timeout);
            this.ws!.off('message', handler);
            resolve(response.result);
          }
        } catch (error) {
          console.error('Error parsing widget properties:', error);
        }
      };
      
      this.ws!.on('message', handler);
      this.ws!.send(JSON.stringify(request));
    });
  }
  
  async highlightWidget(widgetId: string): Promise<void> {
    if (!this.isConnected || !this.ws) {
      return;
    }
    
    const request = {
      id: Date.now().toString(),
      method: 'ext.flutter.inspector.highlight',
      params: {
        objectId: widgetId
      }
    };
    
    this.ws.send(JSON.stringify(request));
  }
  
  async getMemoryUsage(): Promise<any> {
    if (!this.isConnected || !this.ws) {
      return null;
    }
    
    const request = {
      id: Date.now().toString(),
      method: 'getMemoryUsage',
      params: {}
    };
    
    return new Promise((resolve) => {
      const timeout = setTimeout(() => resolve(null), 3000);
      
      const handler = (data: WebSocket.Data) => {
        try {
          const response = JSON.parse(data.toString());
          if (response.id === request.id) {
            clearTimeout(timeout);
            this.ws!.off('message', handler);
            resolve({
              used: response.result.heapUsage,
              capacity: response.result.heapCapacity,
              external: response.result.externalUsage
            });
          }
        } catch (error) {
          console.error('Error parsing memory data:', error);
        }
      };
      
      this.ws!.on('message', handler);
      this.ws!.send(JSON.stringify(request));
    });
  }
  
  disconnect(): void {
    if (this.ws) {
      this.ws.close();
      this.ws = undefined;
      this.isConnected = false;
    }
  }
}