/**
 * Tauri API Service
 * Handles communication between frontend and Tauri backend
 */

import { invoke } from '@tauri-apps/api/core'

// Generic progress listener utility
export class ProgressListener {
  private unlisten: (() => void) | null = null

  /**
   * Execute a command with progress monitoring
   * @param command - Tauri command name
   * @param params - Command parameters
   * @param eventName - Progress event name to listen to
   * @param onProgress - Progress callback function
   * @returns Promise with command result
   */
  static async executeWithProgress<T = any>(
    command: string,
    params: any,
    eventName: string,
    onProgress?: (progress: any) => void
  ): Promise<T> {
    const listener = new ProgressListener()
    return listener.execute(command, params, eventName, onProgress)
  }

  /**
   * Execute a command with progress monitoring (instance method)
   */
  async execute<T = any>(
    command: string,
    params: any,
    eventName: string,
    onProgress?: (progress: any) => void
  ): Promise<T> {
    try {
      // Set up progress listener if callback provided
      if (onProgress) {
        await this.startListening(eventName, onProgress)
      }

      try {
        const result = await invoke(command, params)
        return JSON.parse(result as string)
      } finally {
        // Clean up listener
        this.stopListening()
      }
    } catch (error) {
      console.error(`Failed to execute command ${command} with progress:`, error)
      throw error
    }
  }

  /**
   * Start listening to progress events
   */
  async startListening(eventName: string, onProgress: (progress: any) => void): Promise<void> {
    const { listen } = await import('@tauri-apps/api/event')
    this.unlisten = await listen(eventName, (event) => {
      onProgress(event.payload)
    })
  }

  /**
   * Stop listening to progress events
   */
  stopListening(): void {
    if (this.unlisten) {
      this.unlisten()
      this.unlisten = null
    }
  }

  /**
   * Cleanup method (can be called manually if needed)
   */
  cleanup(): void {
    this.stopListening()
  }
}

// Utility function for simple one-off progress commands
export async function executeCommandWithProgress<T = any>(
  command: string,
  params: any,
  eventName: string,
  onProgress?: (progress: any) => void
): Promise<T> {
  return ProgressListener.executeWithProgress<T>(command, params, eventName, onProgress)
}

// Types for video processing
export interface VideoProcessRequest {
  input_path: string
  output_path: string
  operation: string
  parameters: Record<string, any>
}

export interface AudioAnalysisRequest {
  file_path: string
  analysis_type: string
}

export interface AIVideoRequest {
  image_path: string
  prompt: string
  duration: string
  model_type: string
  output_path?: string
  timeout?: number
}

export interface BatchAIVideoRequest {
  image_folder: string
  prompts: string[]
  output_folder: string
  duration: string
  model_type: string
  timeout?: number
}

export interface ProjectInfo {
  id: string
  name: string
  path: string
  created_at: string
  modified_at: string
  video_tracks: VideoTrack[]
  audio_tracks: AudioTrack[]
  timeline: {
    duration: number
    zoom: number
    position: number
  }
}

export interface VideoTrack {
  id: string
  name: string
  file_path: string
  start_time: number
  duration: number
}

export interface AudioTrack {
  id: string
  name: string
  file_path: string
  start_time: number
  duration: number
  volume: number
}

// Tauri command wrappers
export class TauriService {
  /**
   * Test connection to backend
   */
  static async greet(name: string): Promise<string> {
    try {
      return await invoke('greet', { name })
    } catch (error) {
      console.error('Failed to greet:', error)
      throw error
    }
  }

  /**
   * Process video with specified operation
   */
  static async processVideo(request: VideoProcessRequest): Promise<any> {
    try {
      const result = await invoke('process_video', { request })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to process video:', error)
      throw error
    }
  }

  /**
   * Analyze audio file
   */
  static async analyzeAudio(request: AudioAnalysisRequest): Promise<any> {
    try {
      const result = await invoke('analyze_audio', { request })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to analyze audio:', error)
      throw error
    }
  }

  /**
   * Get project information
   */
  static async getProjectInfo(projectPath: string): Promise<ProjectInfo> {
    try {
      return await invoke('get_project_info', { projectPath })
    } catch (error) {
      console.error('Failed to get project info:', error)
      throw error
    }
  }

  /**
   * Save project
   */
  static async saveProject(projectInfo: ProjectInfo): Promise<string> {
    try {
      return await invoke('save_project', { projectInfo })
    } catch (error) {
      console.error('Failed to save project:', error)
      throw error
    }
  }

  /**
   * Load project
   */
  static async loadProject(projectPath: string): Promise<ProjectInfo> {
    try {
      return await invoke('load_project', { projectPath })
    } catch (error) {
      console.error('Failed to load project:', error)
      throw error
    }
  }
}

// Video processing operations
export class VideoService {
  /**
   * Trim video to specified duration
   */
  static async trimVideo(
    inputPath: string,
    outputPath: string,
    startTime: number,
    endTime: number
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'trim',
      parameters: { start_time: startTime, end_time: endTime }
    })
  }

  /**
   * Resize video to specified dimensions
   */
  static async resizeVideo(
    inputPath: string,
    outputPath: string,
    width?: number,
    height?: number
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'resize',
      parameters: { width, height }
    })
  }

  /**
   * Crop video to specified region
   */
  static async cropVideo(
    inputPath: string,
    outputPath: string,
    x1: number,
    y1: number,
    x2: number,
    y2: number
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'crop',
      parameters: { x1, y1, x2, y2 }
    })
  }

  /**
   * Adjust video brightness
   */
  static async adjustBrightness(
    inputPath: string,
    outputPath: string,
    factor: number
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'adjust_brightness',
      parameters: { factor }
    })
  }

  /**
   * Adjust video contrast
   */
  static async adjustContrast(
    inputPath: string,
    outputPath: string,
    factor: number
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'adjust_contrast',
      parameters: { factor }
    })
  }

  /**
   * Add text overlay to video
   */
  static async addText(
    inputPath: string,
    outputPath: string,
    text: string,
    options: {
      fontsize?: number
      color?: string
      position?: [string, string]
      duration?: number
    } = {}
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: inputPath,
      output_path: outputPath,
      operation: 'add_text',
      parameters: { text, ...options }
    })
  }

  /**
   * Merge multiple videos
   */
  static async mergeVideos(
    videoPaths: string[],
    outputPath: string
  ): Promise<any> {
    return TauriService.processVideo({
      input_path: '', // Not used for merge
      output_path: outputPath,
      operation: 'merge',
      parameters: { video_paths: videoPaths }
    })
  }
}

// Audio processing operations
export class AudioService {
  /**
   * Analyze rhythm and beat tracking
   */
  static async analyzeRhythm(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'rhythm'
    })
  }

  /**
   * Analyze spectral features
   */
  static async analyzeSpectral(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'spectral'
    })
  }

  /**
   * Analyze tempo
   */
  static async analyzeTempo(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'tempo'
    })
  }

  /**
   * Analyze pitch
   */
  static async analyzePitch(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'pitch'
    })
  }

  /**
   * Analyze energy
   */
  static async analyzeEnergy(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'energy'
    })
  }

  /**
   * Analyze MFCC features
   */
  static async analyzeMFCC(filePath: string): Promise<any> {
    return TauriService.analyzeAudio({
      file_path: filePath,
      analysis_type: 'mfcc'
    })
  }
}

// Project management operations
export class ProjectService {
  /**
   * Create new project
   */
  static async createProject(name: string, description: string = ''): Promise<ProjectInfo> {
    // This would typically call a Python script to create the project
    // For now, we'll create a basic project structure
    const projectInfo: ProjectInfo = {
      id: crypto.randomUUID(),
      name,
      path: `/projects/${name}`,
      created_at: new Date().toISOString(),
      modified_at: new Date().toISOString(),
      video_tracks: [],
      audio_tracks: [],
      timeline: {
        duration: 0,
        zoom: 1,
        position: 0
      }
    }

    await TauriService.saveProject(projectInfo)
    return projectInfo
  }

  /**
   * Load existing project
   */
  static async loadProject(projectPath: string): Promise<ProjectInfo> {
    return TauriService.loadProject(projectPath)
  }

  /**
   * Save project
   */
  static async saveProject(projectInfo: ProjectInfo): Promise<void> {
    await TauriService.saveProject(projectInfo)
  }
}

// AI Video generation operations
export class AIVideoService {
  /**
   * Generate video from single image
   */
  static async generateVideo(request: AIVideoRequest): Promise<any> {
    try {
      console.log('Sending AI video request:', request)
      const result = await invoke('generate_ai_video', { request })
      console.log('Raw result from Tauri:', result)

      const parsedResult = JSON.parse(result as string)
      console.log('Parsed result:', parsedResult)

      // Handle JSON-RPC response format
      if (parsedResult.jsonrpc === "2.0") {
        if (parsedResult.result) {
          // Success response
          console.log('JSON-RPC success result:', parsedResult.result)
          return parsedResult.result
        } else if (parsedResult.error) {
          // Error response
          console.error('JSON-RPC error:', parsedResult.error)
          throw new Error(parsedResult.error.message || 'JSON-RPC error')
        }
      }

      // Fallback: direct result format
      return parsedResult
    } catch (error) {
      console.error('Failed to generate AI video:', error)
      console.error('Error details:', {
        name: error instanceof Error ? error.name : 'Unknown',
        message: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined
      })
      throw error
    }
  }

  /**
   * Batch generate videos from multiple images
   */
  static async batchGenerateVideos(request: BatchAIVideoRequest): Promise<any> {
    try {
      console.log('Sending batch AI video request:', request)
      const result = await invoke('batch_generate_ai_videos', { request })
      console.log('Raw batch result from Tauri:', result)

      const parsedResult = JSON.parse(result as string)
      console.log('Parsed batch result:', parsedResult)

      // Handle JSON-RPC response format
      if (parsedResult.jsonrpc === "2.0") {
        if (parsedResult.result) {
          // Success response
          console.log('JSON-RPC batch success result:', parsedResult.result)
          return parsedResult.result
        } else if (parsedResult.error) {
          // Error response
          console.error('JSON-RPC batch error:', parsedResult.error)
          throw new Error(parsedResult.error.message || 'JSON-RPC batch error')
        }
      }

      // Fallback: direct result format
      return parsedResult
    } catch (error) {
      console.error('Failed to batch generate AI videos:', error)
      console.error('Batch error details:', {
        name: error instanceof Error ? error.name : 'Unknown',
        message: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined
      })
      throw error
    }
  }

  /**
   * Test AI video environment
   */
  static async testEnvironment(): Promise<any> {
    try {
      const result = await invoke('test_ai_video_environment')
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to test AI video environment:', error)
      throw error
    }
  }
}

// AI Video generation operations with progress
export class AIVideoProgressService {
  /**
   * Generate video with progress monitoring
   */
  static async generateVideoWithProgress(
    imagePath: string,
    prompt: string,
    outputPath: string,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    return executeCommandWithProgress(
      'generate_video_with_progress',
      { imagePath, prompt, outputPath },
      'video-generation-progress',
      onProgress
    )
  }
}

// Data processing operations
export class DataProcessingService {
  /**
   * Process data with progress monitoring
   */
  static async processDataWithProgress(
    inputFile: string,
    outputFile: string,
    processingType: string,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    const request = { input_file: inputFile, output_file: outputFile, processing_type: processingType }
    return executeCommandWithProgress(
      'process_data_with_progress',
      { request },
      'data-processing-progress',
      onProgress
    )
  }

  /**
   * Batch convert files with progress monitoring
   */
  static async batchConvertFilesWithProgress(
    filePaths: string[],
    outputFormat: string,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    return executeCommandWithProgress(
      'batch_convert_files_with_progress',
      { filePaths, outputFormat },
      'file-conversion-progress',
      onProgress
    )
  }
}

// Machine Learning operations
export class MLService {
  /**
   * Train model with progress monitoring
   */
  static async trainModelWithProgress(
    datasetPath: string,
    modelType: string,
    epochs: number,
    learningRate: number,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    const request = { dataset_path: datasetPath, model_type: modelType, epochs, learning_rate: learningRate }
    return executeCommandWithProgress(
      'train_model_with_progress',
      { request },
      'model-training-progress',
      onProgress
    )
  }
}

// Template management operations
export class TemplateService {
  /**
   * Batch import templates from a folder
   */
  static async batchImportTemplates(sourceFolder: string): Promise<any> {
    try {
      const request = { source_folder: sourceFolder }
      const result = await invoke('batch_import_templates', { request })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to batch import templates:', error)
      throw error
    }
  }

  /**
   * Batch import templates with progress monitoring
   */
  static async batchImportTemplatesWithProgress(
    sourceFolder: string,
    onProgress?: (progress: any) => void
  ): Promise<any> {
    const request = { source_folder: sourceFolder }
    return executeCommandWithProgress(
      'batch_import_templates_with_progress',
      { request },
      'template-import-progress',
      onProgress
    )
  }

  /**
   * Get all templates
   */
  static async getTemplates(): Promise<any> {
    try {
      const result = await invoke('get_templates')
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to get templates:', error)
      throw error
    }
  }

  /**
   * Get template detail with tracks and segments
   */
  static async getTemplateDetail(templateId: string): Promise<any> {
    try {
      const result = await invoke('get_template_detail', { templateId })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to get template detail:', error)
      throw error
    }
  }

  /**
   * Get a specific template
   */
  static async getTemplate(templateId: string): Promise<any> {
    try {
      const result = await invoke('get_template', { templateId })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to get template:', error)
      throw error
    }
  }

  /**
   * Delete a template
   */
  static async deleteTemplate(templateId: string): Promise<any> {
    try {
      const result = await invoke('delete_template', { templateId })
      return JSON.parse(result as string)
    } catch (error) {
      console.error('Failed to delete template:', error)
      throw error
    }
  }
}
