<script setup lang="ts">
import text2videoService from '@/api/service/text2videoService'
import userService from '@/api/service/userService'
import LoginDialog from '@/components/LoginDialog.vue'
import VideoCrop from '@/components/VideoCrop.vue'
import { useAuthStore } from '@/stores/state'
import exportFile from '@/utils/exportFile'
import utils from '@/utils/utils'
import {
  ElMessage,
  genFileId,
  type UploadInstance,
  type UploadProps,
  type UploadRawFile
} from 'element-plus'
import { nextTick, onMounted, reactive, ref } from 'vue'
const authStore = useAuthStore()

const debug = ref(import.meta.env.MODE === 'production' ? false : true)
// const debug = ref(false);
const loading = ref(false)
const title = ref('生成数字人视频')
const isLoginDialogVisible = ref(false)
const isVideoCropDialogVisible = ref(false)
const cropVideo = ref({
  type: 'show_image_or_video',
  url: '',
  postiion: []
})
const isMobile = ref(utils.checkIsMobile())
const form = reactive({
  task_id: '',
  lang: '<|zh|>',
  text: '',
  sample_audio_path: '',
  sample_video_path: '',
  sample_video_url: '',
  show_image_or_video_path: '',
  show_image_or_video_url: '',
  bgm: '',
  final_video: '',
  sample_video_crop_area: [],
  show_image_or_video_crop_area: [],
  subtitle_type: "color",
  subtitle_style: {
    EffectColorStyle: 'CS0003-000023',
    FontSize: 50,
    Position: 0.8
  }
})

onMounted(() => {
  document.title = title.value
  if (!debug) {
    form.text = ''
    form.sample_audio_path = ''
    form.sample_video_path = ''
    form.show_image_or_video_path = ''
    form.sample_video_url = ''
    form.show_image_or_video_url = ''
    form.bgm = ''
  }
  if (!authStore.isLoggedIn) {
    isLoginDialogVisible.value = true
  }
  console.log('isMobile=', isMobile.value)
})

// =========== 上传通用 Begin ===========
const actionUrl = ref(
  import.meta.env.MODE === 'production' ? '/file' : import.meta.env.VITE_APP_BASE_API + '/file'
)
const handleUploadError = (error: Error) => {
  ElMessage({
    message: String(error.message),
    type: 'error'
  })
}
const handleBeforeUpload = async (file: any) => {
  const isLt1M = file.size / 1024 / 1024 <= 50
  if (!isLt1M) {
    ElMessage.error('文件大小不能超过 50MB')
    return false
  }
}
// =========== 上传通用 END ===========

// =========== 上传音频 Begin ===========
const upload_sample_audio = ref<UploadInstance>()
const UploadSampleAudioSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.sample_audio_path = val.data[0].path
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败：' + val.message,
      type: 'error'
    })
  }
}
const handleUploadSampleAudioExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_sample_audio.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_sample_audio.value!.handleStart(file)
  // 提交上传
  upload_sample_audio.value!.submit()
}
const handleUploadSampleAudioRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_sample_audio.value!.clearFiles()
  form.sample_audio_path = ''
}
// =========== 上传音频 END ===========

// =========== 上传采样视频 Begin ===========
const upload_sample_video = ref<UploadInstance>()
const UploadSampleVideoSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.sample_video_path = val.data[0].path
    form.sample_video_url = val.data[0].url
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败：' + val.message,
      type: 'error'
    })
  }
}
const handleUploadSampleVideoExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_sample_video.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_sample_video.value!.handleStart(file)
  // 提交上传
  upload_sample_video.value!.submit()
}
const handleUploadSampleVideoRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_sample_video.value!.clearFiles()
  form.sample_video_path = ''
}
// =========== 上传采样视频 END ===========

// =========== 上传拼接视频或图片 Begin ===========
const upload_show_image_or_video = ref<UploadInstance>()
const UploadShowImageOrVideoSuccess = (val: Wm.UploadResult) => {
  if (val.code == 0) {
    form.show_image_or_video_path = val.data[0].path
    form.show_image_or_video_url = val.data[0].url
    ElMessage({
      message: '上传成功',
      type: 'success'
    })
  } else {
    ElMessage({
      message: '上传失败：' + val.message,
      type: 'error'
    })
  }
}
const handleUploadShowImageOrVideoExceed: UploadProps['onExceed'] = (files) => {
  // 清除已上传的文件
  upload_show_image_or_video.value!.clearFiles()
  // 获取超出限制的第一个文件
  const file = files[0] as UploadRawFile
  // 给文件分配一个新的唯一标识
  file.uid = genFileId()
  // 手动触发文件上传
  upload_show_image_or_video.value!.handleStart(file)
  // 提交上传
  upload_show_image_or_video.value!.submit()
}
const handleUploadShowImageOrVideoRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  // 清除已上传的文件
  upload_show_image_or_video.value!.clearFiles()
  form.show_image_or_video_path = ''
}
// =========== 上传拼接视频或图片 END ===========

// 生成视频
const onGenVideo = async () => {
  if (
    !form.text || form.text.length == 0
  ) {
    ElMessage({
      message: '请输入文案',
      type: 'error'
    })
    return
  }
  if (
    !form.sample_video_path || form.sample_video_path.length == 0
  ) {
    ElMessage({
      message: '请上传出镜人物视频',
      type: 'error'
    })
    return
  }
  try {
    // 初始化task_id转移到这里，防止界面不刷新，导致新旧视频相互重叠
    form.task_id = utils.genDateTimeStr()
    console.log('task_id=', form.task_id)
    let video_param: any = {
      task_id: form.task_id,
      lang: form.lang,
      text: form.text,
      sample_audio_path: form.sample_audio_path,
      sample_video_path: form.sample_video_path,
      show_image_or_video_path: form.show_image_or_video_path,
      bgm: '',
      subtitle_type: form.subtitle_type,
      subtitle_style: JSON.stringify(form.subtitle_style),
    }
    if (form.sample_video_crop_area.length > 0) {
      video_param.sample_video_crop_area = JSON.stringify(form.sample_video_crop_area)
    }
    if (form.show_image_or_video_crop_area.length > 0) {
      video_param.show_image_or_video_crop_area = JSON.stringify(form.show_image_or_video_crop_area)
    }
    const result = await text2videoService.submitGenDigitHumanVideo(video_param)
    console.log(result)
    form.final_video = ''
    form.final_video = result + '?v=' + utils.genDateTimeStr()
  } catch (error: any) {
    // console.error(error);
    ElMessage({
      message: error,
      type: 'error'
    })
  }
}

const showCropVideoDialog = (typp: 'show_image_or_video' | 'sample_video') => {
  cropVideo.value.type = typp
  if (typp == 'show_image_or_video') {
    cropVideo.value.url = form.show_image_or_video_url
    cropVideo.value.postiion = form.show_image_or_video_crop_area
  } else {
    cropVideo.value.url = form.sample_video_url
    cropVideo.value.postiion = form.sample_video_crop_area
  }
  if (!cropVideo.value.url) {
    ElMessage.warning({
      message: '请先上传视频'
    })
    return
  }
  isVideoCropDialogVisible.value = true
}

const handleCrop = (val: any) => {
  console.log('handleCrop', val)
  if (cropVideo.value.type == 'show_image_or_video') {
    form.show_image_or_video_crop_area = val
  } else {
    form.sample_video_crop_area = val
  }
}

// 下载视频
const onDownloadVideo = async () => {
  if (!form.final_video) {
    ElMessage.warning({
      message: '请先生成视频'
    })
    return
  }
  const url = form.final_video
  const arr_name = url.split('/');
  const file_name = arr_name[arr_name.length - 1]; // 获取文件名
  if (isMobile.value) {
    try {
        const fileBlob = await (await fetch(url)).blob();
        const blobUrl = URL.createObjectURL(fileBlob);
        
        // 创建一个隐藏的链接元素
        const link = document.createElement('a');
        link.href = blobUrl;
        link.download = file_name; // 设置下载文件名
        
        // 触发点击事件
        document.body.appendChild(link); // 将链接添加到 DOM
        link.click(); // 模拟点击下载
        document.body.removeChild(link); // 移除链接
        
        // 释放 URL 对象
        URL.revokeObjectURL(blobUrl);

        ElMessage('下载成功了 (Download success)');
    } catch (error) {
        console.error('下载失败:', error);
        ElMessage.error({
            message: '下载失败'
        });
    }
  } else {
    await fetch(url)
      .then((url) => url.blob())
      .then((blob) => {
        exportFile.getVideoFile(blob, file_name);
      })
      .catch((error) => {
        ElMessage.error({
          message: '下载失败：' + error.message
        });
      });
  }
}
</script>

<!-- ============================================================================================================ -->
<!-- ============================================================================================================ -->
<!-- ============================================================================================================ -->

<template>
  <main
    class="home-container"
    :class="{
      'home-container-mobile': isMobile
    }"
  >
    <!-- 标题 -->
    <el-divider content-position="left">{{ title }}</el-divider>
    <el-form
      :model="form"
      label-width="114px"
      v-loading="loading"
      :label-position="isMobile ? 'top' : 'left'"
    >
      <!-- 文案 -->
      <el-form-item label="文案">
        <el-input
          v-model="form.text"
          :autosize="{ minRows: 2, maxRows: isMobile ? 10 : 5 }"
          type="textarea"
          placeholder="Please input"
        />
      </el-form-item>
      <!-- 出镜人物 -->
      <el-form-item label="出镜人物">
        <el-upload
          ref="upload_sample_video"
          :show-file-list="true"
          :limit="1"
          accept=".mp4,.MP4"
          :action="actionUrl"
          :on-success="UploadSampleVideoSuccess"
          :on-exceed="handleUploadSampleVideoExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadSampleVideoRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <el-button type="danger" size="small" @click.stop="showCropVideoDialog('sample_video')">
            裁剪视频画面
          </el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #0000ff; background-color: #e6f7ff">
              请录制一段出镜人的视频，说话时的嘴型能够清晰分辨，20秒左右即可。上传的文件格式为
              mp4，不大于 50M
            </div>
          </template>
        </el-upload>
      </el-form-item>

      <!-- 采样声音 -->
      <el-form-item label="采样声音">
        <el-upload
          ref="upload_sample_audio"
          :show-file-list="true"
          :limit="1"
          accept=".wav,.WAV"
          :action="actionUrl"
          :on-success="UploadSampleAudioSuccess"
          :on-exceed="handleUploadSampleAudioExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadSampleAudioRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #0000ff; background-color: #e6f7ff">
              这里可以上传一段说话的声音，比如朗读一段文字，20秒左右即可。文件格式为 wav，不大于
              50M。也可以不上传，不传则默认用出镜人的声音
            </div>
          </template>
        </el-upload>
      </el-form-item>

      <!-- 拼接视频或图片 -->
      <el-form-item label="拼接视频或图片">
        <el-upload
          ref="upload_show_image_or_video"
          :show-file-list="true"
          :limit="1"
          accept=".mp4,.MP4,.png,.PNG,.jpg,.JPG,.jpeg,.JPEG"
          :action="actionUrl"
          :on-success="UploadShowImageOrVideoSuccess"
          :on-exceed="handleUploadShowImageOrVideoExceed"
          :on-error="handleUploadError"
          :before-upload="handleBeforeUpload"
          :on-remove="handleUploadShowImageOrVideoRemove"
        >
          <el-button type="primary" size="small">上传</el-button>
          <el-button
            type="danger"
            size="small"
            @click.stop="showCropVideoDialog('show_image_or_video')"
          >
          裁剪视频画面
          </el-button>
          <template #tip>
            <div class="el-upload__tip" style="color: #0000ff; background-color: #e6f7ff">
              这里可以上传一段视频(mp4)或一张图片(jpg, png),
              作为最终视频的上半部分，也可以不上传，不传则只生成数字人视频
            </div>
          </template>
        </el-upload>
      </el-form-item>

      <!-- 结果 -->
      <el-form-item label="生成">
        <el-button type="primary" @click="onGenVideo">生成视频</el-button>
        <el-button type="success" @click="onDownloadVideo">下载视频</el-button>
      </el-form-item>
      <el-form-item v-if="form.final_video">
        <video :src="form.final_video" class="example-final-video" controls></video>
      </el-form-item>
    </el-form>
  </main>
  <LoginDialog v-model:visible="isLoginDialogVisible"></LoginDialog>
  <VideoCrop
    v-model:visible="isVideoCropDialogVisible"
    :url="cropVideo.url"
    :cropArea="cropVideo.postiion"
    @crop="handleCrop"
  ></VideoCrop>
</template>

<style lang="scss" scoped>
.home-container {
  width: 100%;
  .example-final-video-wrapper {
    width: 360px;
    .example-final-video-container {
      position: relative;
      width: 360px;
      padding-bottom: 177.78%; /* 16:9 比例 (9 / 16 = 0.5625) */
      height: 0;
      overflow: hidden;
      .example-final-video {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
      }
    }
  }

  .example-final-video {
    width: 360px;
    height: 640px;
    object-fit: cover;
  }

  &.home-container-mobile {
    // .example-final-video-wrapper {
    //   width: 100%;

    //   .example-final-video-container {
    //     width: 100%;
    //   }
    // }
    .example-final-video {
      width: 100%;
      height: auto;
      object-fit: cover;
    }
  }
}
</style>

<style lang="scss">
.home-container {
  .el-table .el-table__cell {
    z-index: calc(var(--el-table-index) -1);
  }
}
.dashed-div {
  border: 1px dashed #999;
  margin: 5px 0;
  padding: 2px;
}
</style>
