import { PickerUtil } from '@pura/picker_utils'
import { TitleBar } from '../../../../view/TitleBar'
import { BusinessError, systemDateTime } from '@kit.BasicServicesKit'
import { AppUtil, FileUtil, JSONUtil, PasteboardUtil, StrUtil } from '@pura/harmony-utils'
import { ToastUtils } from '../../../../utils/ToastUtils'
import { fileIo } from '@kit.CoreFileKit'
import { LoadingDialog } from '../../../../dialog/LoadingDialog'
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog'
import { EventConstants } from '../../../../common/EventConstants'
import { TipDialog } from '../../../../dialog/TipDialog'
import { avSessionManager } from '../../../../manager/AVSessionManager'
import { MP4Parser } from '@ohos/mp4parser'
import { QCloud } from 'qcloudfileflash'
import { Constants } from '../../../../common/Constants'
import { VoiceRecognizeResultEntity } from '../../../../entity/VoiceRecognizeResultEntity'
import { AuthViewModel } from '../../../../viewModel/AuthViewModel'
import { VipAuthEntity } from '../../../../entity/VipAuthEntity'
import { LoginManager } from '../../../../manager/LoginGlobalManager'
import { RouterUrls } from '../../../../common/RouterUrls'
import { router } from '@kit.ArkUI'
import { EventReportManager } from '../../../../manager/EventReportManager'
import { ConfigManager } from '../../../../manager/UserConfigManager'
import { media } from '@kit.MediaKit'

@Entry
@ComponentV2
struct AudioToTextPage {
  private viewModel: AuthViewModel = new AuthViewModel(this.getUIContext())
  private controller: VideoController = new VideoController()
  private avPlayer?: media.AVPlayer = undefined

  @Local resultText?: string
  @Local audioUri?: string
  @Local currentTime: number = 0
  @Local durationTime: number = 0
  @Local isPlaying: boolean = false
  @Local isSuccess: boolean = false

  @Monitor('viewModel.authInfo')
  onPermissionInfoChange(monitor: IMonitor) {
    const info = monitor.value()?.now as VipAuthEntity;
    if (info.auth) {
      if (!LoginManager.isLogin()) {
        this.getUIContext().getRouter().pushUrl({url: RouterUrls.LOGIN_PAGE, params: {from: 1}}, router.RouterMode.Single)
        return;
      }
      this.doSave()
    } else {
      if (!info.auth_ad) {
        this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'videoToText'}})
        EventReportManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'videoToText')
        return;
      }
    }
  }

  @Monitor('viewModel.errorCode')
  onErrorCodeChange(monitor: IMonitor) {
    const errorCode = monitor.value()?.now as number;
    if (errorCode === 12002 || errorCode === 12003 || errorCode === 12004) {
      this.getUIContext().getRouter().pushUrl({url: RouterUrls.RECHARGE_DIAMOND_PAGE});
      EventReportManager.eventReport(EventConstants.JUMP_TO_RECHARGE_DIAMOND, 'videoToText')
      ToastUtils.show('M币已用完')
    }
  }

  aboutToAppear(): void {
    this.initPlayer()
  }

  onPageHide(): void {
    if (this.avPlayer) {
      this.avPlayer.pause()
    }
  }

  aboutToDisappear(): void {
    if (this.avPlayer) {
      this.avPlayer.release()
    }
  }

  async initPlayer() {
    this.avPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数
    this.setAVPlayerCallback();
  }

  doSave() {
    if (this.resultText) {
      PasteboardUtil.setDataTextSync(this.resultText)
      this.isSuccess = false
      ToastUtils.show('复制成功')
    }
  }

  copyAudio() {
    LoadingDialog.show(this.getUIContext())
    this.isSuccess = false
    let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp3`
    if (FileUtil.accessSync(cachePath)) {
      FileUtil.unlinkSync(cachePath)
    }
    let file = FileUtil.openSync(this.audioUri!!, fileIo.OpenMode.READ_ONLY)
    // 复制文件到缓存目录下
    FileUtil.copyFileSync(file.fd, cachePath)
    FileUtil.closeSync(file)

    this.recognizeAudio(cachePath)
      .then((result) => {
        if (result !== null) {
          this.resultText = result.flash_result[0].text
          this.isSuccess = true
          this.isPlaying = false
          ToastUtils.show('处理成功')
        } else {
          ToastUtils.show('处理失败')
        }
        LoadingDialog.dismiss()
      })
      .catch((e: BusinessError) => {
        console.log(e.message)
        ToastUtils.show('处理失败')
        LoadingDialog.dismiss()
      })
  }

  async recognizeAudio(uri: string): Promise<VoiceRecognizeResultEntity|null> {
    let builder = new QCloud.FileFlash.Builder()
    builder.appID = Constants.QCLOUD_APP_ID
    builder.secretID = Constants.QCLOUD_SECRET_ID
    builder.secretKey = Constants.QCLOUD_SECRET_KEY
    // builder.token = this._token
    builder.setApiParam(QCloud.FileFlash.kEngineType, '16k_zh')
    builder.setApiParam(QCloud.FileFlash.kVoiceFormat, 'mp3')
    builder.setApiParam(QCloud.FileFlash.kFilterDirty, 0)
    builder.setApiParam(QCloud.FileFlash.kFilterModal, 0)
    builder.setApiParam(QCloud.FileFlash.kFilterPunc, 0)
    builder.setApiParam(QCloud.FileFlash.kConvertNumMode, 1)
    builder.setApiParam(QCloud.FileFlash.kWordInfo, 0)
    builder.setApiParam(QCloud.FileFlash.kSpeakerDiarization, 1)
    try {
      let file = FileUtil.openSync(uri, fileIo.OpenMode.READ_ONLY)
      const stat = FileUtil.lstatSync(uri)
      const buffer = new ArrayBuffer(stat.size)
      FileUtil.readSync(file.fd, buffer)
      FileUtil.closeSync(file)
      let result = await builder.build(buffer).task
      let voiceResult = JSONUtil.jsonToBean(result, VoiceRecognizeResultEntity)
      return Promise.resolve(voiceResult)
    } catch (e) {
      console.error(e)
      return Promise.reject(e)
    }
  }

  selectAudio() {
    PickerUtil.selectDocument({maxSelectNumber: 1, fileSuffixFilters: ['.mp3']})
      .then(async (uris) => {
        if (uris.length != 0) {
          this.isSuccess = false
          await this.avPlayer?.reset()
          this.audioUri = uris[0]
          this.resultText = undefined
          // 打开相应的资源文件地址获取fd
          let file = await fileIo.open(this.audioUri)
          this.avPlayer!!.url = 'fd://' + file.fd
        }
      })
  }

  showDownloadDialog() {
    DownloadDialog.show(this.getUIContext(), { status: DownloadStatus.COMPLETED, totalSize: 0, progress: 0, totalCount: 1, index: 0, callback: {
      confirm: () => {
        AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, 0)
        this.getUIContext().getRouter().back()
      }
    } })
  }

  // 注册avplayer回调函数
  setAVPlayerCallback() {
    this.avPlayer!!.on('error', (err) => {
      console.error(`播放器发生错误，错误码：${err.code}, 错误信息：${err.message}`);
      // 调用reset重置资源，触发idle状态
      this.isPlaying = false
      this.avPlayer!!.reset();
      avSessionManager.deactivate()
    })
    // 状态机变化回调函数
    this.avPlayer!!.on('stateChange', async (state, reason) => {
      switch (state) {
        case 'initialized':
          console.info('资源初始化完成');
          // 资源初始化完成，开始准备文件
          this.avPlayer!!.prepare();
          break;
        case 'prepared':
          console.info('资源准备完成');
          // 资源准备完成，开始准备文件
          this.durationTime = Math.trunc(this.avPlayer!!.duration / 1000)
          this.currentTime = this.avPlayer!!.currentTime;
          break;
        case 'completed':
          console.info('播放完成');
          this.isPlaying = false
          this.avPlayer!!.off('bufferingUpdate')
          AppStorage.setOrCreate('currentTime', this.durationTime);
          avSessionManager.deactivate()
          break;
        case 'playing':
          console.info('播放开始');
          this.isPlaying = true
          break;
        case 'released':
        case 'stopped':
        case 'error':
        case 'paused':
          console.info('播放暂停');
          this.isPlaying = false
          avSessionManager.deactivate()
          break;
      }
    })
    // 时间上报监听函数
    this.avPlayer!!.on('timeUpdate', (time: number) => {
      this.currentTime = Math.trunc(time / 1000);
    });
  }

  formatTime(time: number): string {
    let minute: number = 0
    let second: number = 0
    if (time > 60) {
      minute = Math.trunc(time / 60)
      second = time % 60
      if (minute < 10) {
        if (second < 10) {
          return `0${minute}:0${second}`
        } else {
          return `0${minute}:${second}`
        }
      } else {
        if (second < 10) {
          return `${minute}:0${second}`
        } else {
          return `${minute}:${second}`
        }
      }
    } else {
      second = time
      if (second < 10) {
        return `00:0${second}`
      } else {
        return `00:${second}`
      }
    }
  }

  onBackPress(): boolean | void {
    if (this.isSuccess && this.resultText) {
      TipDialog.show(this.getUIContext(), {title:'温馨提示', content:'文本尚未复制，是否确定退出？', callback: {
        confirm: () => {
          this.getUIContext().getRouter().back()
        }
      }})
      return true
    }
    return false
  }

  build() {
    Column() {
      TitleBar({ title: '语音转文字' })

      Stack() {
        Stack() {
          Column() {
            Image($r('app.media.ic_add_audio')).width(40).height(40)
            Text('请上传音频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
          }
        }
        .width('100%')
        .aspectRatio(1)
        .borderRadius(20)
        .backgroundColor(Color.White)
        .shadow({radius: 10, color: '#1a9399a1'})
        .onClick(() => {
          this.selectAudio()
        })
      }
      .width('100%')
      .height('auto')
      .padding({left: 32, right: 32})
      .margin({top: 40})
      .visibility(this.audioUri ? Visibility.None : Visibility.Visible)

      Row() {
        Image(this.isPlaying ? $r('app.media.ic_audio_pause2') : $r('app.media.ic_audio_play2'))
          .width(40)
          .height(40)
          .margin({ right: 16 })
          .onClick(async () => {
            if (this.isPlaying) {
              this.avPlayer!!.pause()
            } else {
              await avSessionManager.activate()
              this.avPlayer!!.play()
            }
          })
        Text(this.formatTime(this.currentTime)).width(45).fontColor($r('app.color.color_999999')).fontSize(16)
        Slider({
          value: this.currentTime,
          min: 0,
          max: this.durationTime
        })
          .blockColor(Color.White)
          .trackColor($r('app.color.color_eeeeee'))
          .onChange((value: number, mode: SliderChangeMode) => {
            this.avPlayer!!.seek(value * 1000, 2); // 设置视频播放的进度跳转到value处
            this.currentTime = value;
          })
          .layoutWeight(1)
        Text(this.formatTime(this.durationTime)).width(45).fontColor($r('app.color.color_999999')).fontSize(16)
      }
      .height(60)
      .borderRadius(30)
      .borderWidth(1)
      .borderColor('#DADEE5')
      .backgroundColor(Color.White)
      .margin({left: 12, top: 40, right: 12})
      .padding({left: 16, right: 16})
      .visibility(this.audioUri ? Visibility.Visible : Visibility.None)

      Stack({alignContent: Alignment.Top}) {
        Column() {
          Row() {
            Image($r('app.media.ic_star')).width(22).height(22)
            Text('文本结果').fontColor($r('app.color.color_212226')).fontSize(15).fontWeight(FontWeight.Medium).margin({left: 4})
          }
          Divider().strokeWidth(1).color($r('app.color.color_eeeeee')).margin({top: 12})
          Text('暂无数据').width('100%').layoutWeight(1).textAlign(TextAlign.Center).fontSize(14).fontColor($r('app.color.color_1a1a1a'))
            .margin({top: 12})
            .visibility(this.resultText === '' ? Visibility.Visible : Visibility.None)
          Scroll() {
            Text(this.resultText).width('100%').fontColor($r('app.color.color_212226')).fontSize(14).margin({top: 12})
          }
          .layoutWeight(1)
          .align(Alignment.TopStart)
          .scrollBar(BarState.Off)
        }
        .width('100%')
        .height('100%')
        .alignItems(HorizontalAlign.Start)
        .borderRadius(10)
        .borderWidth(1)
        .borderColor('#DADEE5')
        .backgroundColor(Color.White)
        .padding(12)
      }
      .layoutWeight(1)
      .margin({top: 30, bottom: 20})
      .padding({left: 16, right: 16})
      .visibility(StrUtil.isNotNull(this.resultText) ? Visibility.Visible : Visibility.None)

      Blank().layoutWeight(1).visibility(StrUtil.isNotNull(this.resultText) ? Visibility.None : Visibility.Visible)

      Stack() {
        Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
          .width('100%')
          .height(46)
          .fontColor(Color.White)
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
          .backgroundColor($r('app.color.color_466afd'))
          .onClick(() => {
            this.avPlayer?.pause()
            if (this.audioUri) {
              this.copyAudio()
            } else {
              ToastUtils.show('请上传音频')
            }
          })
          .visibility(StrUtil.isNull(this.resultText) ? Visibility.Visible : Visibility.None)

        Row() {
          Button({ type: ButtonType.Capsule, stateEffect: true }) {
            Row() {
              Image($r('app.media.ic_reupload')).width(20).height(20)
              Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
            }
          }
          .height(46)
          .layoutWeight(1)
          .borderWidth(1)
          .borderColor($r('app.color.color_466afd'))
          .backgroundColor(Color.Transparent)
          .onClick(() => {
            this.controller.stop()
            this.selectAudio()
          })

          Blank().width(9)

          Button({ type: ButtonType.Capsule, stateEffect: true }) {
            Row() {
              Image($r('app.media.ic_copy_text')).width(20).height(20)
              Text('复制文本').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
            }
          }
          .height(46)
          .layoutWeight(1)
          .backgroundColor($r('app.color.color_466afd'))
          .onClick(() => {
            this.controller.stop()
            if (ConfigManager.isAiAuthEnable() && this.durationTime > 60) {
              this.viewModel.checkVip()
            } else {
              this.doSave()
            }
          })
        }
        .visibility(StrUtil.isNotNull(this.resultText) ? Visibility.Visible : Visibility.None)
      }
      .padding({left: 16, top: 9, right: 16, bottom: 30 })
      .backgroundColor(Color.White)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.window_background'))
  }
}