import { DebugState } from '../types';

export interface TidewaveCapabilities {
  framework: 'phoenix' | 'rails' | 'unknown';
  endpoint: string;
  available_tools: string[];
  version?: string;
}

export interface TidewaveRequest {
  tool: string;
  params?: Record<string, any>;
}

export interface TidewaveResponse {
  success: boolean;
  data?: any;
  error?: string;
  metadata?: {
    execution_time?: number;
    framework_version?: string;
  };
}

export class TidewaveIntegration {
  private capabilities: Map<string, TidewaveCapabilities> = new Map();
  
  /**
   * Detect if a URL has Tidewave enabled and what capabilities it has
   */
  async detectTidewave(url: string): Promise<TidewaveCapabilities | null> {
    try {
      // Try Phoenix endpoint first
      const phoenixEndpoint = `${url}/tidewave/mcp`;
      let response = await this.testEndpoint(phoenixEndpoint);
      
      if (response) {
        const capabilities: TidewaveCapabilities = {
          framework: 'phoenix',
          endpoint: phoenixEndpoint,
          available_tools: response.tools || [],
          version: response.version
        };
        this.capabilities.set(url, capabilities);
        return capabilities;
      }
      
      // Try Rails endpoint
      const railsEndpoint = `${url}/tidewave`;
      response = await this.testEndpoint(railsEndpoint);
      
      if (response) {
        const capabilities: TidewaveCapabilities = {
          framework: 'rails',
          endpoint: railsEndpoint,
          available_tools: response.tools || [],
          version: response.version
        };
        this.capabilities.set(url, capabilities);
        return capabilities;
      }
      
      return null;
    } catch (error) {
      console.error('Tidewave detection failed:', error);
      return null;
    }
  }
  
  /**
   * Test if a Tidewave endpoint is accessible
   */
  private async testEndpoint(endpoint: string): Promise<any> {
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);
      
      const response = await fetch(`${endpoint}/capabilities`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        signal: controller.signal
      });
      
      clearTimeout(timeoutId);
      
      if (response.ok) {
        return await response.json();
      }
      return null;
    } catch {
      return null;
    }
  }
  
  /**
   * Execute a Tidewave tool for enhanced debugging/testing
   */
  async executeTool(url: string, request: TidewaveRequest): Promise<TidewaveResponse> {
    const capabilities = this.capabilities.get(url);
    if (!capabilities) {
      return {
        success: false,
        error: 'Tidewave not available for this URL'
      };
    }
    
    if (!capabilities.available_tools.includes(request.tool)) {
      return {
        success: false,
        error: `Tool '${request.tool}' not available. Available: ${capabilities.available_tools.join(', ')}`
      };
    }
    
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 30000);
      
      const response = await fetch(`${capabilities.endpoint}/${request.tool}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        body: JSON.stringify(request.params || {}),
        signal: controller.signal
      });
      
      clearTimeout(timeoutId);
      
      const data = await response.json();
      
      return {
        success: response.ok,
        data: response.ok ? data : undefined,
        error: response.ok ? undefined : data.error || `HTTP ${response.status}`,
        metadata: {
          execution_time: data.execution_time,
          framework_version: capabilities.version
        }
      };
    } catch (error) {
      return {
        success: false,
        error: `Tidewave execution failed: ${error instanceof Error ? error.message : String(error)}`
      };
    }
  }
  
  /**
   * Get application logs through Tidewave
   */
  async getLogs(url: string, options: {
    level?: string;
    limit?: number;
    since?: string;
  } = {}): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'logs',
      params: options
    });
  }
  
  /**
   * Execute custom code for testing/debugging
   */
  async evaluateCode(url: string, code: string, context?: Record<string, any>): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'eval',
      params: { code, context }
    });
  }
  
  /**
   * Get application documentation
   */
  async getDocumentation(url: string, path?: string): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'documentation',
      params: { path }
    });
  }
  
  /**
   * Execute SQL queries for database testing
   */
  async executeSQL(url: string, query: string, params?: any[]): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'sql',
      params: { query, params }
    });
  }
  
  /**
   * Trace application processes
   */
  async traceProcesses(url: string, pattern?: string): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'processes',
      params: { pattern }
    });
  }
  
  /**
   * Search project dependencies
   */
  async searchDependencies(url: string, query: string): Promise<TidewaveResponse> {
    return this.executeTool(url, {
      tool: 'dependencies',
      params: { query }
    });
  }
  
  /**
   * Enhanced debugging state with Tidewave data
   */
  async enhanceDebugState(url: string, debugState: DebugState): Promise<DebugState> {
    const capabilities = this.capabilities.get(url);
    if (!capabilities) {
      return debugState;
    }
    
    // Add Tidewave-specific information to debug state
    const tidewaveData: any = {
      framework: capabilities.framework,
      available_tools: capabilities.available_tools,
      version: capabilities.version
    };
    
    // Get logs if available
    if (capabilities.available_tools.includes('logs')) {
      const logs = await this.getLogs(url, { limit: 50 });
      if (logs.success) {
        tidewaveData.recent_logs = logs.data;
      }
    }
    
    // Get process information if available
    if (capabilities.available_tools.includes('processes')) {
      const processes = await this.traceProcesses(url);
      if (processes.success) {
        tidewaveData.processes = processes.data;
      }
    }
    
    return {
      ...debugState,
      tidewave: tidewaveData
    };
  }
  
  /**
   * Generate test assertions using Tidewave application knowledge
   */
  async generateTestAssertions(url: string, scenario: string): Promise<string[]> {
    const capabilities = this.capabilities.get(url);
    if (!capabilities) {
      return [];
    }
    
    const framework = capabilities.framework;
    const assertions: string[] = [];
    
    // Framework-specific test generation
    if (framework === 'phoenix') {
      assertions.push(`# Phoenix LiveView test assertions for: ${scenario}`);
      assertions.push('assert has_element?(view, "[data-testid=\\"#{scenario}\\"]")');
      assertions.push('refute has_element?(view, ".error")');
    } else if (framework === 'rails') {
      assertions.push(`# Rails system test assertions for: ${scenario}`);
      assertions.push(`expect(page).to have_content("${scenario}")`);
      assertions.push('expect(page).not_to have_css(".error")');
    }
    
    // Use Tidewave documentation to enhance assertions
    if (capabilities.available_tools.includes('documentation')) {
      const docs = await this.getDocumentation(url, scenario);
      if (docs.success && docs.data) {
        // Parse documentation to generate more specific assertions
        assertions.push(`# Generated from application documentation`);
        // Add doc-based assertions here
      }
    }
    
    return assertions;
  }
}

export const tidewave = new TidewaveIntegration();