import type { InterfaceHandler } from './handler/core'

import type { BusinessParams, PrivateCustomEventName, PublicCustomEventName, SsmlConfig, SystemConfig } from './types'
import { isIos } from '@minto-ai/tools'
import {
  AudioActuator,
  ByteBufferNotIos,
  CreateSsml,
  DecodeDataBaShanIos,
  DecodeDataIos,
  DecodeDataNotIos,
  TextSplit,
  TtsRequestBaShanIos,
  TtsRequestIos,
  TtsRequestNotIos,
} from './process'
import { SystemStatus } from './types'
import { createEventBus } from './utils/event-bus'

class TtsController {
  private isEqualBaShan: boolean = false

  private isNeedCreateSsml: boolean = false

  private textSplitInstance: TextSplit

  private createSsmlInstance: CreateSsml

  private audioActuatorInstance!: AudioActuator

  // iOS 处理器实例
  private ttsRequestIosInstance!: TtsRequestIos
  private decodeDataIosInstance!: DecodeDataIos

  // 巴山 IOS 处理器实例
  private ttsRequestBaShanIosInstance!: TtsRequestBaShanIos
  private decodeDataShanIosInstance!: DecodeDataBaShanIos

  // 非iOS 处理器实例
  private ttsRequestNotIosInstance!: TtsRequestNotIos
  private byteBufferNotIosInstance!: ByteBufferNotIos
  private decodeDataNotIosInstance!: DecodeDataNotIos

  public systemStatus: SystemStatus = SystemStatus.OFFLINE

  public $bus = createEventBus<PublicCustomEventName | PrivateCustomEventName>()

  /**
   * TTS控制器构造函数
   * @param systemConfig - 系统配置
   * @param businessParams - 业务参数
   * @param ssmlConfig - SSML 配置
   */
  constructor(systemConfig: SystemConfig, businessParams: BusinessParams, ssmlConfig: SsmlConfig) {
    this.isEqualBaShan = businessParams.provider === '100'

    this.textSplitInstance = new TextSplit()

    if (this.isEqualBaShan) {
      this.isNeedCreateSsml = false
    }
    else {
      if (businessParams.text_type === 'ssml') {
        this.isNeedCreateSsml = true
      }
      else {
        this.isNeedCreateSsml = false
      }
    }

    this.createSsmlInstance = new CreateSsml()
    this.createSsmlInstance.initProperty(ssmlConfig)

    this.audioActuatorInstance = new AudioActuator()

    // 根据设备类型初始化对应的处理器
    if (isIos()) {
      if (this.isEqualBaShan) {
        this.ttsRequestBaShanIosInstance = new TtsRequestBaShanIos()
        this.decodeDataShanIosInstance = new DecodeDataBaShanIos()
        this.ttsRequestBaShanIosInstance.initProperty(systemConfig, businessParams)
      }
      else {
        this.ttsRequestIosInstance = new TtsRequestIos()
        this.decodeDataIosInstance = new DecodeDataIos()
        this.ttsRequestIosInstance.initProperty(systemConfig, businessParams)
      }
    }
    else {
      this.ttsRequestNotIosInstance = new TtsRequestNotIos()
      this.byteBufferNotIosInstance = new ByteBufferNotIos()
      this.decodeDataNotIosInstance = new DecodeDataNotIos()
      this.ttsRequestNotIosInstance.initProperty(systemConfig, businessParams)
    }

    this.textSplitInstance.setExecuteController(this)

    this.createSsmlInstance.setExecuteController(this)

    // 设置处理器控制器
    if (isIos()) {
      if (this.isEqualBaShan) {
        this.ttsRequestBaShanIosInstance.setExecuteController(this)
        this.decodeDataShanIosInstance.setExecuteController(this)
        this.audioActuatorInstance.setExecuteController(this)
      }
      else {
        this.ttsRequestIosInstance.setExecuteController(this)
        this.decodeDataIosInstance.setExecuteController(this)
        this.audioActuatorInstance.setExecuteController(this)
      }
    }
    else {
      this.ttsRequestNotIosInstance.setExecuteController(this)
      this.byteBufferNotIosInstance.setExecuteController(this)
      this.decodeDataNotIosInstance.setExecuteController(this)
      this.audioActuatorInstance.setExecuteController(this)
    }

    // 链接处理器
    if (isIos()) {
      if (this.isEqualBaShan) {
        // 巴山iOS设备：TextSplit -> CreateSsml（可选）-> TtsRequestBaShanIos -> DecodeDataBaShanIos -> AudioActuator
        if (this.isNeedCreateSsml) {
          this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler)
          this.createSsmlInstance.linkHandler(this.ttsRequestBaShanIosInstance as unknown as InterfaceHandler)
        }
        else {
          this.textSplitInstance.linkHandler(this.ttsRequestBaShanIosInstance as unknown as InterfaceHandler)
        }
        this.ttsRequestBaShanIosInstance.linkHandler(this.decodeDataShanIosInstance as unknown as InterfaceHandler)
        this.decodeDataShanIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler)
      }
      else {
        // iOS设备：TextSplit -> CreateSsml （可选）-> TtsRequestIos -> DecodeDataIos -> AudioActuator
        if (this.isNeedCreateSsml) {
          this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler)
          this.createSsmlInstance.linkHandler(this.ttsRequestIosInstance as unknown as InterfaceHandler)
        }
        else {
          this.textSplitInstance.linkHandler(this.ttsRequestIosInstance as unknown as InterfaceHandler)
        }
        this.ttsRequestIosInstance.linkHandler(this.decodeDataIosInstance as unknown as InterfaceHandler)
        this.decodeDataIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler)
      }
    }
    else {
      // 非iOS设备：TextSplit -> CreateSsml （可选）-> TtsRequestNotIos -> ByteBufferNotIos -> DecodeDataNotIos -> AudioActuator
      if (this.isNeedCreateSsml) {
        this.textSplitInstance.linkHandler(this.createSsmlInstance as unknown as InterfaceHandler)
        this.createSsmlInstance.linkHandler(this.ttsRequestNotIosInstance as unknown as InterfaceHandler)
      }
      else {
        this.textSplitInstance.linkHandler(this.ttsRequestNotIosInstance as unknown as InterfaceHandler)
      }
      this.ttsRequestNotIosInstance.linkHandler(this.byteBufferNotIosInstance as unknown as InterfaceHandler)
      this.byteBufferNotIosInstance.linkHandler(this.decodeDataNotIosInstance as unknown as InterfaceHandler)
      this.decodeDataNotIosInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler)
    }

    this.bindEvent()
  }

  /**
   * 绑定事件监听器
   */
  private bindEvent(): void {
    /**
     * 音频首次播放
     */
    this.$bus.on('_audioActuatorBeforeFirstExecute', () => {
      this.emit('audioFirstStart')
    })

    /**
     * 应用出错，触发 appFinish 事件
     */
    this.$bus.on('_appError', (error) => {
      this.finish()
      this.emit('appError', error)
    })

    /**
     * 应用被销毁，触发 appFinish 事件
     */
    this.$bus.on('_appFinish', () => {
      this.finish()
    })
  }

  /**
   * 进入待机状态，等待传入文本数据
   */
  public start(): TtsController {
    if (this.systemStatus === SystemStatus.EXECUTE) {
      return this
    }

    this.textSplitInstance.triggerHandlerActive()

    this.createSsmlInstance.triggerHandlerActive()

    if (isIos()) {
      if (this.isEqualBaShan) {
        this.ttsRequestBaShanIosInstance.triggerHandlerActive()
        this.decodeDataShanIosInstance.triggerHandlerActive()
        this.audioActuatorInstance.triggerHandlerActive()
      }
      else {
        this.ttsRequestIosInstance.triggerHandlerActive()
        this.decodeDataIosInstance.triggerHandlerActive()
        this.audioActuatorInstance.triggerHandlerActive()
      }
    }
    else {
      this.ttsRequestNotIosInstance.triggerHandlerActive()
      this.byteBufferNotIosInstance.triggerHandlerActive()
      this.decodeDataNotIosInstance.triggerHandlerActive()
      this.audioActuatorInstance.triggerHandlerActive()
    }

    this.systemStatus = SystemStatus.EXECUTE

    return this
  }

  /**
   * 传入文本数据
   * @param text - 待转换的文本
   */
  public send(text: string): TtsController {
    if (this.systemStatus !== SystemStatus.EXECUTE) {
      return this
    }

    this.textSplitInstance.handle(text)

    return this
  }

  /**
   * 应用停止处理传入的文本，但是并不会停止音频播放
   */
  public end(): TtsController {
    if (this.systemStatus !== SystemStatus.EXECUTE) {
      return this
    }

    this.textSplitInstance.handle(null)
    this.textSplitInstance.isHandleDataAcceptedComplete = true

    return this
  }

  /**
   * 停止所有处理器，并且重置状态，触发 appFinish 事件
   */
  public finish(): void {
    if (this.systemStatus === SystemStatus.OFFLINE) {
      return
    }

    this.textSplitInstance.triggerHandlerFinish()

    this.createSsmlInstance.triggerHandlerFinish()

    if (isIos()) {
      if (this.isEqualBaShan) {
        this.ttsRequestBaShanIosInstance.triggerHandlerFinish()
        this.decodeDataShanIosInstance.triggerHandlerFinish()
        this.audioActuatorInstance.triggerHandlerFinish()
      }
      else {
        this.ttsRequestIosInstance.triggerHandlerFinish()
        this.decodeDataIosInstance.triggerHandlerFinish()
        this.audioActuatorInstance.triggerHandlerFinish()
      }
    }
    else {
      this.ttsRequestNotIosInstance.triggerHandlerFinish()
      this.byteBufferNotIosInstance.triggerHandlerFinish()
      this.decodeDataNotIosInstance.triggerHandlerFinish()
      this.audioActuatorInstance.triggerHandlerFinish()
    }

    this.systemStatus = SystemStatus.OFFLINE

    this.emit('appFinish')
  }

  /**
   * 发射事件
   * @param eventName - 事件名称
   * @param data - 事件数据
   */
  private emit<T>(eventName: PublicCustomEventName, data?: T): void {
    this.$bus.emit(eventName, data)
  }

  /**
   * 监听事件
   * @param eventName - 事件名称
   * @param callback - 回调函数
   */
  public on(eventName: PublicCustomEventName, callback: (data?: any) => void): TtsController {
    this.$bus.on(eventName, callback)
    return this
  }

  /**
   * 静音
   */
  public mute(): void {
    this.audioActuatorInstance.mute()
  }

  /**
   * 取消静音
   */
  public unmute(): void {
    this.audioActuatorInstance.unmute()
  }

  /**
   * 暂停播放
   */
  public pause(): void {
    this.audioActuatorInstance.pause()
  }

  /**
   * 恢复播放
   */
  public resume(): void {
    this.audioActuatorInstance.resume()
  }
}

export default TtsController
