<script setup lang="ts">
import {
  deleteDocument,
  downloadDocument, getDocument,
  getReviewResult,
  getReviewResultPlan,
  getReviewStatus,
  reviewDocument,
  revisionOfAuditResults,
  saveDocumentApi,
  setReviewPlan,
  uploadDocument
} from '@/api/review'
import router from '@/router'
import { MsgConfirm, MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
import { ElMessage } from 'element-plus'
import { cloneDeep, isEmpty } from 'lodash-es'
import { onMounted, ref, onBeforeUnmount, computed } from 'vue'
import 'aieditor/dist/style.css'
import AuditItem from './components/AuditItem.vue'
import AuditLoading from './components/AuditLoading.vue'
import ProgrammeSelect from './components/ProgrammeSelect.vue'
import Editor from './components/Editor.vue'
import { useRoute } from 'vue-router'
import { auditType } from './config'

import useStore from '@/stores'
import { marked } from 'marked'

const { docs } = useStore()
const { query } = useRoute()

const pageTitle = ref('')
const editorRef = ref<any>(null)
const loading = ref<boolean>(false)

// 回显数据
onMounted(async () => {
  if (query?.id) {
    try {
      loading.value = true
      const { data } = await getDocument(query?.id as string);
      documentId.value = query?.id as string;
      file.value = data;
      pageTitle.value = data?.name;
      config.value = data.review_plan.map((v: any) => v.review_plan_id);
      configText.value = data.review_plan.map((v: any) => v.review_plan_name).join(',');
      await getResult()
    } finally {
      loading.value = false
    }
  }
})
// 退出页面清除loading状态
onBeforeUnmount(() => {
  docs.setAuditLoadingStatus('')
  docs.setAuditLoadingText('')
  clearInterval(timer.value)
})

const back = async () => {
  if (!query?.id && showConfig.value) {
    if (documentId.value || config.value?.length) {
      const res = await MsgConfirm('提示', '文档已修改，是否保存？')
      if (res) {
        await deleteDocument([documentId.value])
        router.go(-1)
        return;
      }
    }
  }
  await closeConfirm(() => {
    router.go(-1)
  })
}
const download = async () => {
  try {
    await saveDocumentApi(documentId.value, editorRef.value.editor?.getHTML())
    const res = await downloadDocument(documentId.value)
    const blob = new Blob([res], {
      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    })

    const downloadLink = document.createElement('a')
    downloadLink.href = window.URL.createObjectURL(blob)
    downloadLink.download = `${pageTitle.value}.docx`

    document.body.appendChild(downloadLink)

    // 触发下载
    downloadLink.click()

    // 移除链接
    document.body.removeChild(downloadLink)

    // 释放URL对象
    window.URL.revokeObjectURL(downloadLink.href)
  } catch (error) {
    console.error('下载文件时发生错误:', error)
    MsgWarning('文件下载失败，请稍后重试！')
  }
}
const saveDocument = async () => {
  await saveDocumentApi(documentId.value, editorRef.value.editor?.getHTML())
  ElMessage.success('保存成功！')
}

// true 显示配置 false 显示结果
const showConfig = ref<boolean>(true)

const position = ref<string>('') // 立场设置
const documentId = ref<string>('') // 文档ID
const file: any = ref({}) // 上查的文档

/**
 * 上传文件方法
 * @param f
 */
const uploadFile = async (f: any) => {
  // 检查文件类型
  const allowedTypes = ['docx', 'pdf']
  const fileExtension = f.name.split('.').pop()?.toLowerCase()
  if (!allowedTypes.includes(fileExtension)) {
    ElMessage.error('文件类型不支持，仅支持word、pdf格式')
    return
  }

  // 检查文件大小（10M = 100 * 1024 * 1024 字节）
  const maxSize = 10 * 1024 * 1024
  if (f.size > maxSize) {
    ElMessage.error('文件大小超过限制，最多支持10M')
    return
  }
  if (file.value?.loading) return
  file.value = {
    ...f,
    loading: true
  }
  try {
    const formData = new FormData()
    formData.append('file', f.raw)
    formData.append('file_name', f.name)
    formData.append('file_type', query?.type as string)
    const result = await uploadDocument(formData)
    MsgSuccess('上传成功')
    documentId.value = result.data.id
    pageTitle.value = result.data?.name;
    editorRef.value.editor.commands?.setContent(marked('<p>' + result.data.content.replace(/\n/g, '</p><p>') + '</p>'), { emitUpdate: true })
    file.value = {
      ...file.value,
      ...result.data,
      loading: false
    }
  } catch (e) {
    MsgError('上传失败')
    file.value = {}
    console.log(e)
  }
}
// 删除文档
const handleDelData = async (e: any) => {
  try {
    e.stopPropagation()
    await deleteDocument([documentId.value])
    ElMessage.success('删除成功！')
    file.value = {}
  } catch (e) {
    ElMessage.error('删除失败！')
  }
}
// 结果显示数组
const result: any = ref([])
const allResult: any = ref([])
const resultPlan: any = ref([])
const initHtml = ref<string>('<p></p>');
const isShowResult = ref<boolean>()
// 获取结果
const getResult = async () => {
  try {
    const { data } = await getReviewResult(documentId.value)
    if (data.result) {
      editorRef.value.editor.commands?.setContent(marked('<p>' + data.result.replace(/\n/g, '</p><p>') + '</p>'), { emitUpdate: true })
    }
    if (data.status === 3) {
      // 调用获取审核结果接口
      showConfig.value = false
      pageTitle.value = data?.name;
      isShowResult.value = (data?.has_risk_point || 0) === 1
      initHtml.value = cloneDeep(editorRef.value.editor.getHTML());
      resultPlan.value = [{ name: '全部', review_plan_id: 0 }, ...data?.review_plan] || []
      if (resultPlan.value.length !== 0) {
        activeName.value = resultPlan.value[0]?.review_plan_id
        allResult.value = data?.rule_results || []
        result.value = allResult.value
      }
    }
  } catch (error) {
    MsgError('获取审核结果失败')
    console.error(error)
  }
}
// 获取结果方案
const getResultPlan = async (review_plan_id: string) => {
  try {
    const { data } = await getReviewResultPlan(documentId.value, review_plan_id)
    // 调用获取审核结果接口
    showConfig.value = false
    result.value = data.rules
  } catch (error) {
    MsgError('获取审核结果失败')
    console.error(error)
  }
}
const timer: any = ref(null)
// 轮询状态接口
const pollingStatus = async () => {
  timer.value = setInterval(async () => {
    try {
      const { data } = await getReviewStatus(documentId.value)

      if (data.status === 2) {
        clearInterval(timer.value)
        docs.setAuditLoadingStatus('error')
        docs.setAuditLoadingText('审核失败')
      } else if (data.status === 3) {
        clearInterval(timer.value)
        MsgSuccess('审核完成')
        docs.setAuditLoadingStatus('success')
        docs.setAuditLoadingText('')
        await getResult()
      }
    } catch (error) {
      clearInterval(timer.value)
      MsgError('获取审核状态失败')
      docs.setAuditLoadingText('')
      console.error(error)
    }
  }, 2000)
}
// 开始审核文档
const handleCreate = async (action: any) => {
  try {
    if (isEmpty(file.value)) {
      return MsgWarning('您还未上传文档，请先上传文档')
    }
    if (isEmpty(config.value)) {
      return MsgWarning('您还未选择审核方案，请先选择审核方案')
    }
    docs.setAuditLoadingStatus('')
    docs.setAuditLoadingText('AI正在审核中')
    await saveDocumentApi(documentId.value, editorRef.value.editor?.getHTML())
    const data = await setReviewPlan(documentId.value, {
      review_plan_id: config.value,
      position: +(query?.type as any) === 0 ? '' : position.value,
      white_list: []
    })
    pageTitle.value = data.data?.name;
    await reviewDocument(documentId.value, action)
    await pollingStatus()
  } catch (e) {
    console.log(e)
  }
}

// 富文本插件的问题，导致增加一个阻塞任务
function sleep() {
  return new Promise((resolve) => {
    setTimeout(() => {
      return resolve(true)
    }, 0)
  })
}

// 定位到原文
const handleLocate = async (v: any) => {
  let target: any = [];
  (v.corrections || []).map((item: any) => {
    const el = document.querySelectorAll(`[uuid~="${item.uuid}"]`) || null
    if (el && el.length !== 0) {
      target.push(el[0])
    }
  })
  if (target && (target || []).length !== 0) {
    for (let i = 0; i < target.length; i++) {
      const el = target[i]

       /* 判断元素是否在可视区内 */
       const rect = el.getBoundingClientRect()
      const isInViewport = (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
      )

      /* 如果不在可视区，则滚动到元素位置 */
      if (!isInViewport) {
        el.scrollIntoView({
          behavior: 'smooth',
          block: 'center' // 垂直方向居中显示
        })
        // 等待滚动完成
        await new Promise(resolve => setTimeout(resolve, 300))
      }


      el.classList.add('active-highlight')
      setTimeout(() => {
        el.classList.remove('active-highlight')
      }, 1000)
      await sleep()
    }
  } else {
    return MsgWarning('审查失败，请重新审查！')
  }
}
// 接受修订
const handleAccept = async (v: any, i:number) => {
  const oldHtml = editorRef.value?.editor?.getHTML()
  // 创建临时DOM元素
  const tempDiv = document.createElement('div')
  tempDiv.innerHTML = oldHtml
  let flag = false;
  try {
    (v.corrections || []).map((item: any) => {
      const target = tempDiv.querySelectorAll(`[uuid~="${item.uuid}"]`) || null
      if (target && (target || []).length !== 0) {
        // 给第一个target替换文本内容
        if (target.length > 0) {
          target[0].innerHTML = item.corrected_char
        }
        // 删除多余的target dom
        for (let i = 1; i < target.length; i++) {
          target[i].remove()
        }
      } else {
        flag = true;
      }
    })
    if (flag) {
      result.value[i].reception = 0
      return MsgWarning('审查失败，请重新审查！')
    }
    await revisionOfAuditResults(documentId.value, {
      id: v.id,
      review_rule_id: v.rule_id,
      reception: '1'
    })
    result.value[i].reception = 1
    const newHtml = tempDiv.innerHTML
    editorRef.value?.editor.commands.setContent(newHtml)
  } catch (e: any) {
    if (e?.response?.data?.detail) {
      return MsgError(e?.response?.data?.detail)
    }
    console.log(e)
  }
}
// 撤销修订
const handleReject = async (v: any, i: number) => {
  const oldHtml = editorRef.value?.editor?.getHTML()
  // 创建临时DOM元素
  const tempDiv = document.createElement('div')
  tempDiv.innerHTML = oldHtml
  let flag = false;
  try {
    (v.corrections || []).map((item: any) => {
      const target = tempDiv.querySelectorAll(`[uuid~="${item.uuid}"]`) || null
      if (target && (target || []).length !== 0) {
        // 给第一个target替换文本内容
        if (target.length > 0) {
          target[0].innerHTML = item.original_char
        }
        // 删除多余的target dom
        for (let i = 1; i < target.length; i++) {
          target[i].remove()
        }
      } else {
        flag = true;
      }
    })
    if (flag) {
      result.value[i].reception = 0
      return MsgWarning('审查失败，请重新审查！')
    }
    await revisionOfAuditResults(documentId.value, {
      id: v.id,
      review_rule_id: v.rule_id,
      reception: '2'
    })
    result.value[i].reception = 2
    const newHtml = tempDiv.innerHTML
    editorRef.value?.editor.commands.setContent(newHtml)
  } catch (e: any) {
    if (e?.response?.data?.detail) {
      return MsgError(e?.response?.data?.detail)
    }
    console.log(e)
  }
}
// 设置页面
const config = ref([])
const configText = ref('')
const dialogVisible = ref(false)
const handleConfirm = async (val: any) => {
  config.value = val?.checkIds
  configText.value = val?.checkNames.join(',')
  dialogVisible.value = false
}

const activeName = ref('')
// 结果页tab切换，筛选对应的数据
const handleChangeActiveName = () => {
  result.value = [];
  if (+activeName.value === 0) {
    result.value = allResult.value;
    return
  }
  getResultPlan(activeName.value);
}


const closeConfirm = async (call: Function) => {
  if (initHtml.value !== editorRef.value.editor.getHTML()) {
    const res = await MsgConfirm('提示', '文档已修改，是否保存？')
    if (res) {
      await saveDocument()
      call()
    }
  } else {
    call()
  }
}

const toggleShowConfig = () => {
  closeConfirm(() => {
    showConfig.value = true;
  })
}

const buttonDisabled = computed(() => isEmpty(config.value) || isEmpty(file.value))
</script>
<template>
  <div class="audit-container" v-loading="loading" element-loading-text="获取数据中">
    <div class="header">
      <div class="left-action">
        <el-icon @click="back" class="pointer" style="margin-right: 12px">
          <ArrowLeftBold />
        </el-icon>
        <span>{{ pageTitle }}</span>
      </div>
      <el-space :size="20">
        <el-button type="primary" style="width: 80px" @click="download" :disabled="showConfig">下载</el-button>
        <el-button type="primary" style="width: 80px" @click="saveDocument" :disabled="showConfig">保存</el-button>
      </el-space>
    </div>
    <section class="container">
      <Editor class="container-left" ref="editorRef" />
      <div class="container-right">
        <div class="container-right-title">
          <el-icon v-if="!showConfig" class="pointer" style="margin-right: 12px; position: relative; top: 2px"
            @click="toggleShowConfig">
            <ArrowLeftBold />
          </el-icon>
          <span style="margin-bottom: 8px; display: inline-block">{{
            showConfig ? auditType[query.type as any] : '审核结果'
          }}</span>
          <div v-if="showConfig" class="desc">请在左侧输入内容或上传文档后开始审核</div>
        </div>
        <div class="container-right-content" v-if="showConfig">
          <el-form-item label="内容参考" label-position="top" required>
            <el-upload style="width: 100%; height: 100%" action="#" :auto-upload="false" :show-file-list="false"
              :on-change="uploadFile" accept=".docx,.pdf" :disabled="file?.loading || file?.name">
              <div class="container-right-content-upload">
                <el-space class="container-right-content-upload-button" v-if="!file.name && !file.loading">
                  <img src="@/assets/webapp/upload.svg" alt="" />
                  上传
                </el-space>
                <template v-else>
                  <div class="left">
                    <span v-if="file.loading">
                      <img src="@/assets/webapp/loading.svg" class="loading-img" alt="" />
                      上传中
                    </span>
                    <span v-else>{{ file.name }}</span>
                  </div>
                  <div class="right" @click="handleDelData">删除</div>
                </template>
              </div>
            </el-upload>
          </el-form-item>
          <div style="
              font-weight: 400;
              font-size: 12px;
              color: #999999;
              line-height: 20px;
              margin-bottom: 20px;
            ">
            * 上传文件支持word、pdf，文件不超过10mb
          </div>
          <el-form-item label="立场设置" label-position="top" v-if="+(query?.type as any) === 1">
            <el-input v-model="position" placeholder="请输入立场" />
          </el-form-item>
          <el-form-item label="审核设置" label-position="top" required>
            <div class="audit-config">
              审核方案
              <div class="left">
                {{ configText || '请选择' }}
              </div>
              <div class="right pointer" @click="dialogVisible = true">
                <img src="@/assets/webapp/14.svg" alt="" style="position: relative; top: 4px" />
              </div>
            </div>
          </el-form-item>
        </div>
        <div class="container-right-content" v-else-if="isShowResult">
          <el-tabs v-model="activeName" @tab-change="handleChangeActiveName">
            <el-tab-pane v-for="item in resultPlan" :label="item.name" :name="item.review_plan_id" />
          </el-tabs>
          <div class="container-right-content-list">
            <div class="validation-status" v-if="result.length === 0">
              <div class="risk-no">
                <el-icon style="margin-right: 4px">
                  <Check />
                </el-icon>
                内容无风险
              </div>
            </div>
            <template v-else>
              <AuditItem
                v-for="(v, i) in result"
                :id="v.id"
                :key="i"
                :originalText="v.corrections"
                :revisionText="v.suggestion"
                :basisText="v.basis"
                :isHighRisk="v.risk_level === 1"
                :revised="v.reception"
                @locate="() => handleLocate(v)"
                @accept="() => handleAccept(v, i)"
                @reject="() => handleReject(v, i)" />
            </template>
          </div>
        </div>
        <div class="container-right-content" v-else>
          <div class="validation-status">
            <div class="risk-no">
              <el-icon style="margin-right: 4px">
                <Check />
              </el-icon>
              内容无风险
            </div>
          </div>
        </div>
        <el-button v-if="showConfig" :disabled="buttonDisabled" style="width: 100%" type="primary"
          @click="handleCreate(0)">开始审核</el-button>
      </div>
    </section>
    <AuditLoading @refresh="handleCreate(1)" />
    <ProgrammeSelect :visible="dialogVisible" v-if="dialogVisible" @cancel="dialogVisible = false" :check-ids="config"
      @confirm="handleConfirm" />
  </div>
</template>

<style scoped lang="scss">
.audit-container {
  width: 100%;
  height: 100vh;
  background: #f4f8ff;
  position: relative;

  .header {
    height: 60px;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    background: #fff;
    border-radius: 24px 24px 0 0;
    padding-left: 32px;
    padding-right: 28px;

    .left-action {
      font-size: 18px;
      font-weight: bold;
      width: 70%;
      align-items: center;
      display: flex;
    }
  }

  .container {
    padding-top: 20px;
    padding-bottom: 20px;
    padding-left: 20px;
    height: calc(100vh - 100px);
    display: flex;
    flex-direction: row;
    justify-content: space-between;

    &-left {
      width: 70%;
    }

    &-right {
      width: 30%;
      padding: 20px 20px 0 20px;
      display: flex;
      flex-direction: column;

      &-title {
        font-weight: 600;
        font-size: 16px;
        color: #333333;

        margin-bottom: 21px;

        .desc {
          font-weight: 400;
          font-size: 12px;
          color: #666666;
          padding-bottom: 15px;
          border-bottom: 1px solid rgba(0, 0, 0, 0.1);
        }
      }

      &-content {
        flex: 1;
        overflow: hidden;

        &-upload,
        .audit-config {
          width: 100%;
          height: 34px;
          display: flex;
          background: #ffffff;
          border-radius: 4px 4px 4px 4px;
          border: 1px solid rgba(0, 0, 0, 0.1);
          align-items: center;
          justify-content: space-between;

          &-button {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: 400;
            font-size: 12px;
            color: #3067ef;
          }

          .left {
            margin-left: 12px;
            font-weight: 400;
            font-size: 12px;
            color: #8c8c8c;
            line-height: 20px;
            flex: 2;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;

            .loading-img {
              width: 12px;
              height: 12px;
              position: relative;
              top: 2px;
            }

            @keyframes rotate {
              from {
                transform: rotate(0deg);
              }

              to {
                transform: rotate(360deg);
              }
            }

            .loading-img {
              animation: rotate 2s linear infinite;
            }
          }

          .right {
            margin-right: 12px;
            font-weight: 400;
            font-size: 12px;
            color: #3067ef;
            line-height: 20px;
            cursor: pointer;
          }

          .disabled {
            color: #888c87;
          }
        }

        .audit-config {
          padding-left: 12px;
          box-sizing: border-box;
        }

        &-list {
          height: calc(100% - 51px);
          overflow-y: auto;
        }

        .validation-status {
          height: 40px;
          padding: 1px;
          border-radius: 8px;
          background: radial-gradient(
              circle,
              rgba(48, 103, 239, 1),
              rgba(140, 81, 242, 1),
              rgba(48, 103, 239, 1),
              rgba(173, 211, 249, 1)
          );
          position: relative;

          .risk-no {
            background: #fff;
            border-radius: 8px;
            font-weight: 500;
            font-size: 14px;
            color: #3067ef;
            z-index: 102;
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
          }


          .close {
            position: absolute;
            right: 10px;
            top: 10px;
          }
        }
      }
    }
  }
}
</style>
<style lang="scss">
.audit-container {
  .pointer {
    cursor: pointer;
  }

  .el-upload {
    width: 100% !important;
  }

  .active-highlight {
    animation: highlightBlink 0.5s ease-in-out 2;
    background-color: #3067ef;
    color: white;
  }

  @keyframes highlightBlink {

    0%,
    100% {
      background-color: transparent;
      color: inherit;
    }

    50% {
      background-color: #3067ef;
      color: white;
    }
  }
}
</style>
