import type { InterfaceHandler } from './handler/core'
import type { BusinessParams, PrivateCustomEventName, PublicCustomEventName, SystemConfig } from './types'
import { AudioActuator, DecodeData, ResponseTranscode, TextSplit, TtsRequest } from './process'

import { SystemStatus } from './types'
import { createEventBus } from './utils'

class TtsController {
  private textSplitInstance: TextSplit = new TextSplit()

  private responseTranscodeInstance: ResponseTranscode = new ResponseTranscode()

  private audioActuatorInstance: AudioActuator = new AudioActuator()

  private ttsRequestInstance: TtsRequest = new TtsRequest()

  private decodeDataInstance: DecodeData = new DecodeData()

  public systemStatus: SystemStatus = SystemStatus.OFFLINE

  public $bus = createEventBus<PublicCustomEventName | PrivateCustomEventName>()

  constructor(systemConfig: SystemConfig, businessParams: Partial<BusinessParams> = {}) {
    this.ttsRequestInstance.initProperty(systemConfig, businessParams)

    this.textSplitInstance.setExecuteController(this)
    this.responseTranscodeInstance.setExecuteController(this)
    this.audioActuatorInstance.setExecuteController(this)
    this.ttsRequestInstance.setExecuteController(this)
    this.decodeDataInstance.setExecuteController(this)

    this.textSplitInstance.linkHandler(this.ttsRequestInstance as unknown as InterfaceHandler)
    this.ttsRequestInstance.linkHandler(this.responseTranscodeInstance as unknown as InterfaceHandler)
    this.responseTranscodeInstance.linkHandler(this.decodeDataInstance as unknown as InterfaceHandler)
    this.decodeDataInstance.linkHandler(this.audioActuatorInstance as unknown as InterfaceHandler)

    this.bindEvent()
  }

  private bindEvent(): void {
    /**
     * 音频首次播放
     */
    this.$bus.on('_audioActuatorBeforeFirstExecute', () => {
      this.emit('audioFirstStart')
    })

    this.$bus.on('_appFinish', () => {
      this.finish()
    })
  }

  /**
   *  进入待机状态，等待传入文本数据
   */
  public start(): TtsController {
    if (this.systemStatus === SystemStatus.EXECUTE) {
      return this
    }

    this.textSplitInstance.triggerHandlerActive()
    this.ttsRequestInstance.triggerHandlerActive()
    this.responseTranscodeInstance.triggerHandlerActive()
    this.audioActuatorInstance.triggerHandlerActive()
    this.decodeDataInstance.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.responseTranscodeInstance.triggerHandlerFinish()
    this.audioActuatorInstance.triggerHandlerFinish()
    this.ttsRequestInstance.triggerHandlerFinish()
    this.decodeDataInstance.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()
  }
}

export default TtsController
