import { spawn, exec } from 'child_process'
import { app } from 'electron'
import { is } from '@electron-toolkit/utils'
import path from 'path'
import { controlWindow } from '../ControlWindow'
import { allConfig } from './AllConfig'
import { i18n } from '../i18n'

export class CaptionEngine {
  appPath: string = ''
  command: string[] = []
  process: any | undefined
  processStatus: 'running' | 'stopping' | 'stopped' = 'stopped'

  private getApp(): boolean {
    if (allConfig.controls.customized && allConfig.controls.customizedApp) {
      console.log('[INFO] Using customized engine')
      this.appPath = allConfig.controls.customizedApp
      this.command = allConfig.controls.customizedCommand.split(' ')
    }
    else if (allConfig.controls.engine === 'gummy') {
      allConfig.controls.customized = false
      if(!allConfig.controls.API_KEY && !process.env.DASHSCOPE_API_KEY) {
        controlWindow.sendErrorMessage(i18n('gummy.key.missing'))
        return false
      }
      let gummyName = 'main-gummy'
      if (process.platform === 'win32') {
        gummyName += '.exe'
      }
      if (is.dev) {
        this.appPath = path.join(
          app.getAppPath(),
          'caption-engine', 'dist', gummyName
        )
      }
      else {
        this.appPath = path.join(
          process.resourcesPath, 'caption-engine', gummyName
        )
      }
      this.command = []
      this.command.push('-s', allConfig.controls.sourceLang)
      this.command.push(
        '-t', allConfig.controls.translation ?
        allConfig.controls.targetLang : 'none'
      )
      this.command.push('-a', allConfig.controls.audio ? '1' : '0')
      if(allConfig.controls.API_KEY) {
        this.command.push('-k', allConfig.controls.API_KEY)
      }
    }
    else if(allConfig.controls.engine === 'vosk'){
      allConfig.controls.customized = false
      let voskName = 'main-vosk'
      if (process.platform === 'win32') {
        voskName += '.exe'
      }
      if (is.dev) {
        this.appPath = path.join(
          app.getAppPath(),
          'caption-engine', 'dist', voskName
        )
      }
      else {
        this.appPath = path.join(
          process.resourcesPath, 'caption-engine', voskName
        )
      }
      this.command = []
      this.command.push('-a', allConfig.controls.audio ? '1' : '0')
      this.command.push('-m', `"${allConfig.controls.modelPath}"`)
    }
    console.log('[INFO] Engine Path:', this.appPath)
    console.log('[INFO] Engine Command:', this.command)
    return true
  }

  public start() {
    if (this.processStatus !== 'stopped') {
      return
    }
    if(!this.getApp()){ return }

    try {
      this.process = spawn(this.appPath, this.command)
    }
    catch (e) {
      controlWindow.sendErrorMessage(i18n('engine.start.error') + e)
      console.error('[ERROR] Error starting subprocess:', e)
      return
    }

    this.processStatus = 'running'
    console.log('[INFO] Caption Engine Started, PID:', this.process.pid)

    allConfig.controls.engineEnabled = true
    if(controlWindow.window){
      allConfig.sendControls(controlWindow.window)
      controlWindow.window.webContents.send(
        'control.engine.started',
        this.process.pid
      )
    }

    this.process.stdout.on('data', (data: any) => {
      const lines = data.toString().split('\n');
      lines.forEach((line: string) => {
        if (line.trim()) {
          try {
            const caption = JSON.parse(line);
            if(caption.index === undefined) {
              console.log('[INFO] Engine Bad Output:', caption);
            }
            else allConfig.updateCaptionLog(caption);
          } catch (e) {
            controlWindow.sendErrorMessage(i18n('engine.output.parse.error') + e)
            console.error('[ERROR] Error parsing JSON:', e);
          }
        }
      });
    });

    this.process.stderr.on('data', (data) => {
      if(this.processStatus === 'stopping') return
      controlWindow.sendErrorMessage(i18n('engine.error') + data)
      console.error(`[ERROR] Subprocess Error: ${data}`);
    });

    this.process.on('close', (code: any) => {
      console.log(`[INFO] Subprocess exited with code ${code}`);
      this.process = undefined;
      allConfig.controls.engineEnabled = false
      if(controlWindow.window){
        allConfig.sendControls(controlWindow.window)
        controlWindow.window.webContents.send('control.engine.stopped')
      }
      this.processStatus = 'stopped'
      console.log('[INFO] Caption engine process stopped')
    });
  }

  public stop() {
    if(this.processStatus !== 'running') return
    if (this.process.pid) {
      console.log('[INFO] Trying to stop process, PID:', this.process.pid)
      let cmd = `kill ${this.process.pid}`;
      if (process.platform === "win32") {
        cmd = `taskkill /pid ${this.process.pid} /t /f`
      }
      exec(cmd, (error) => {
        if (error) {
          controlWindow.sendErrorMessage(i18n('engine.shutdown.error') + error)
          console.error(`[ERROR] Failed to kill process: ${error}`)
        }
      })
    }
    else {
      this.process = undefined;
      allConfig.controls.engineEnabled = false
      if(controlWindow.window){
        allConfig.sendControls(controlWindow.window)
        controlWindow.window.webContents.send('control.engine.stopped')
      }
      this.processStatus = 'stopped'
      console.log('[INFO] Process PID undefined, caption engine process stopped')
      return
    }
    this.processStatus = 'stopping'
    console.log('[INFO] Caption engine process stopping')
  }
}

export const captionEngine = new CaptionEngine()
