import axios from 'axios'
import { ElMessage } from 'element-plus'
import { useGetCategoryList } from '@/composables/useGetCategoryList'
import { upload } from '@/utils/upload'
import {
  createBook,
  createCase,
  createResourceCourseware,
  createResourceLessonPlan,
  createResourceOther,
  createResourceVideo,
  createVideo,
  getResourceUploadVideoAuth,
  updateResourceUploadVideoAuth,
} from '../api'
import type { AuthorizePlatform, CaseFileSelectionType, CaseLibraryFile, CaseLibraryItem } from '../types'
import { useCaseLibrary } from './useCaseLibrary'
import { useGetCourseList } from './useGetCourseList'
import { useGetExperimentList } from './useGetExperimentList'

const caseFileTypeMap: Record<CaseFileSelectionType, string> = {
  case: '1',
  ppt: '2',
  book: '3',
  video: '4',
  dataset: '5',
  other: '6',
}

const caseFileSectionConfig: Array<{
  key: CaseFileSelectionType
  title: string
  emptyText: string
}> = [
  { key: 'case', title: '案例原文', emptyText: '暂无案例原文' },
  { key: 'ppt', title: '案例PPT', emptyText: '暂无案例PPT' },
  { key: 'book', title: '案例指导书', emptyText: '暂无案例指导书' },
  { key: 'video', title: '案例操作视频', emptyText: '暂无案例操作视频' },
  { key: 'dataset', title: '案例数据集', emptyText: '暂无案例数据集' },
  { key: 'other', title: '其他资料', emptyText: '暂无其他资料' },
]

const experimentSupportedTypes = new Set<CaseFileSelectionType>(['case', 'book', 'video'])
const resourceSupportedTypes = new Set<CaseFileSelectionType>(['ppt', 'book', 'video', 'dataset', 'other'])

function createEmptySelections(): Record<CaseFileSelectionType, string[]> {
  return {
    case: [],
    ppt: [],
    book: [],
    video: [],
    dataset: [],
    other: [],
  }
}

function getMimeType(fileName: string) {
  const ext = fileName.split('.').pop()?.toLowerCase() || ''
  const mimeMap: Record<string, string> = {
    doc: 'application/msword',
    docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    html: 'text/html',
    pdf: 'application/pdf',
    ppt: 'application/vnd.ms-powerpoint',
    pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    txt: 'text/plain',
    xls: 'application/vnd.ms-excel',
    xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    csv: 'text/csv',
    mp4: 'video/mp4',
  }
  return mimeMap[ext] || 'application/octet-stream'
}

function getFileExtension(fileName: string) {
  return fileName.split('.').pop()?.toLowerCase() || ''
}

function getFileNameWithoutExt(fileName: string) {
  return fileName.replace(/\.[^.]+$/, '')
}

function getAuthorizedName(caseName: string, fileName: string) {
  return `${caseName}-${getFileNameWithoutExt(fileName)}`
}

function getFilesByType(files: CaseLibraryItem['files'], type: string) {
  return files.filter((file) => file.type === type)
}

function buildSummaryText(stats: {
  experiment: { case: number; book: number; video: number }
  resource: { courseware: number; lessonPlan: number; video: number; other: number }
}) {
  const parts: string[] = []
  if (stats.experiment.case || stats.experiment.book || stats.experiment.video) {
    parts.push(
      `实操平台：案例原文 ${stats.experiment.case} 个，指导书 ${stats.experiment.book} 个，视频 ${stats.experiment.video} 个`,
    )
  }
  if (stats.resource.courseware || stats.resource.lessonPlan || stats.resource.video || stats.resource.other) {
    parts.push(
      `统一资源平台：课件 ${stats.resource.courseware} 个，教案 ${stats.resource.lessonPlan} 个，视频 ${stats.resource.video} 个，其他资料 ${stats.resource.other} 个`,
    )
  }
  return parts.join('；')
}

export function useCaseAuthorization() {
  const { list, loading, fetchList } = useCaseLibrary()
  const { courses, updateCourses } = useGetCourseList()
  const { experiments, updateExperiments } = useGetExperimentList()
  const { list: categoryList } = useGetCategoryList()

  const platformSelections = ref<AuthorizePlatform[]>(['experiment'])
  const selectedCourse = ref('')
  const selectedExperiment = ref('')
  const resourceClassification = ref('')
  const selectedCaseId = ref('')
  const fileSelections = ref<Record<CaseFileSelectionType, string[]>>(createEmptySelections())
  const submitting = ref(false)
  const progress = ref(0)
  const progressText = ref('')

  updateCourses()
  fetchList()

  watch(selectedCourse, (val) => {
    selectedExperiment.value = ''
    updateExperiments(val)
  })

  watch(selectedCaseId, () => {
    fileSelections.value = createEmptySelections()
  })

  function isPlatformSelected(platform: AuthorizePlatform) {
    return platformSelections.value.includes(platform)
  }

  function isTypeSelectable(type: CaseFileSelectionType) {
    return (
      (isPlatformSelected('experiment') && experimentSupportedTypes.has(type)) ||
      (isPlatformSelected('resource') && resourceSupportedTypes.has(type))
    )
  }

  watch(
    platformSelections,
    () => {
      const nextSelections = createEmptySelections()
      for (const section of caseFileSectionConfig) {
        nextSelections[section.key] = isTypeSelectable(section.key) ? [...fileSelections.value[section.key]] : []
      }
      fileSelections.value = nextSelections
    },
    { deep: true },
  )

  const selectedCase = computed(() => list.value.find((item) => item.id === selectedCaseId.value) || null)

  const groupedFiles = computed(() => {
    const files = selectedCase.value?.files || []
    return {
      case: getFilesByType(files, caseFileTypeMap.case),
      ppt: getFilesByType(files, caseFileTypeMap.ppt),
      book: getFilesByType(files, caseFileTypeMap.book),
      video: getFilesByType(files, caseFileTypeMap.video),
      dataset: getFilesByType(files, caseFileTypeMap.dataset),
      other: getFilesByType(files, caseFileTypeMap.other),
    }
  })

  const selectedCount = computed(() =>
    caseFileSectionConfig.reduce((total, section) => total + fileSelections.value[section.key].length, 0),
  )

  const selectedItems = computed(() => {
    if (!selectedCase.value) return []
    const result: Array<{
      row: CaseLibraryItem
      type: CaseFileSelectionType
      file: CaseLibraryFile
      authorizeToExperiment: boolean
      authorizeToResource: boolean
    }> = []

    for (const section of caseFileSectionConfig) {
      for (const key of fileSelections.value[section.key]) {
        const file = selectedCase.value.files.find(
          (item) => `${item.type}-${item.url}` === key && item.type === caseFileTypeMap[section.key],
        )
        if (!file) continue
        result.push({
          row: selectedCase.value,
          type: section.key,
          file,
          authorizeToExperiment: isPlatformSelected('experiment') && experimentSupportedTypes.has(section.key),
          authorizeToResource: isPlatformSelected('resource') && resourceSupportedTypes.has(section.key),
        })
      }
    }

    return result
  })

  function handleCaseChange(caseId: string) {
    selectedCaseId.value = caseId
  }

  function getFileKey(file: CaseLibraryFile) {
    return `${file.type}-${file.url}`
  }

  function getAllChecked(type: CaseFileSelectionType) {
    const files = groupedFiles.value[type]
    return !!files.length && fileSelections.value[type].length === files.length
  }

  function handleToggleAll(type: CaseFileSelectionType, checked: boolean) {
    if (!isTypeSelectable(type)) {
      fileSelections.value[type] = []
      return
    }
    fileSelections.value[type] = checked ? groupedFiles.value[type].map((file) => getFileKey(file)) : []
  }

  function setStepProgress(index: number, total: number, ratio: number, label: string) {
    const safeRatio = Math.max(0, Math.min(1, ratio))
    progress.value = Math.round(((index + safeRatio) / total) * 100)
    progressText.value = label
  }

  async function downloadRemoteFile(url: string, fileName: string, index: number, total: number) {
    const response = await axios.get(url, {
      responseType: 'blob',
      onDownloadProgress: (event) => {
        if (!event.total) {
          setStepProgress(index, total, 0.15, `正在下载：${fileName}`)
          return
        }
        const ratio = event.loaded / event.total
        setStepProgress(index, total, ratio * 0.45, `正在下载 ${Math.round(ratio * 100)}%：${fileName}`)
      },
    })
    return new File([response.data], fileName, {
      type: response.data.type || getMimeType(fileName),
    })
  }

  async function uploadDocumentFromCase(url: string, fileName: string, index: number, total: number) {
    const file = await downloadRemoteFile(url, fileName, index, total)
    setStepProgress(index, total, 0.55, `正在上传文件：${fileName}`)
    const uploadedUrl = await upload(file)
    return {
      file,
      url: uploadedUrl,
    }
  }

  async function uploadVideoFromCase(
    url: string,
    fileName: string,
    index: number,
    total: number,
  ) {
    const file = await downloadRemoteFile(url, fileName, index, total)

    return new Promise<string>((resolve, reject) => {
      const uploader = new (window as any).AliyunUpload.Vod({
        userId: '1303984639806000',
        region: 'cn-shanghai',
        partSize: 1048576,
        parallel: 5,
        retryCount: 3,
        retryDuration: 2,
        onUploadstarted(uploadInfo: any) {
          setStepProgress(index, total, 0.55, `正在上传视频：${uploadInfo.file.name}`)
          getResourceUploadVideoAuth({ title: uploadInfo.file.name, file_name: uploadInfo.file.name })
            .then((res: any) => {
              uploader.setUploadAuthAndAddress(
                uploadInfo,
                res.data.upload_auth,
                res.data.upload_address,
                res.data.source_id,
              )
            })
            .catch(reject)
        },
        onUploadSucceed(uploadInfo: any) {
          setStepProgress(index, total, 0.95, `视频上传完成：${uploadInfo.file.name}`)
          resolve(uploadInfo.videoId)
        },
        onUploadFailed(_uploadInfo: any, code: number, message: string) {
          reject(new Error(message || `视频上传失败: ${code}`))
        },
        onUploadProgress(_uploadInfo: any, _totalSize: number, loadedPercent: number) {
          setStepProgress(
            index,
            total,
            0.55 + loadedPercent * 0.4,
            `正在上传视频 ${Math.round(loadedPercent * 100)}%：${fileName}`,
          )
        },
        onUploadTokenExpired(uploadInfo: any) {
          updateResourceUploadVideoAuth({ source_id: uploadInfo.videoId })
            .then((res: any) => {
              uploader.resumeUploadWithAuth(res.data.UploadAuth || res.data.upload_auth || res.UploadAuth)
            })
            .catch(reject)
        },
      })

      uploader.addFile(file, null, null, null, '{"Vod":{}}')
      uploader.startUpload()
    })
  }

  async function submitAuthorize() {
    if (!platformSelections.value.length) {
      ElMessage.warning('请选择授权平台')
      return
    }
    if (isPlatformSelected('experiment') && !selectedExperiment.value) {
      ElMessage.warning('授权到实操平台时请选择课程和实验')
      return
    }
    if (isPlatformSelected('resource') && !resourceClassification.value) {
      ElMessage.warning('授权到统一资源平台时请选择分类')
      return
    }
    if (!selectedItems.value.length) {
      ElMessage.warning('请勾选需要授权的案例文件')
      return
    }

    const actionableItems = selectedItems.value.filter((item) => item.authorizeToExperiment || item.authorizeToResource)
    if (!actionableItems.length) {
      ElMessage.warning('当前授权平台下没有可授权的案例文件')
      return
    }

    const successStats = {
      experiment: { case: 0, book: 0, video: 0 },
      resource: { courseware: 0, lessonPlan: 0, video: 0, other: 0 },
    }

    submitting.value = true
    progress.value = 0
    progressText.value = `准备处理 0/${actionableItems.length}`

    try {
      for (let index = 0; index < actionableItems.length; index += 1) {
        const item = actionableItems[index]
        const { row, type, file, authorizeToExperiment, authorizeToResource } = item
        const authorizedName = getAuthorizedName(row.name, file.name)
        setStepProgress(index, actionableItems.length, 0.05, `准备处理 ${index + 1}/${actionableItems.length}：${file.name}`)

        if (type === 'video') {
          const sourceId = await uploadVideoFromCase(file.url, file.name, index, actionableItems.length)

          if (authorizeToExperiment) {
            setStepProgress(index, actionableItems.length, 0.98, `正在创建实验操作视频：${file.name}`)
            await createVideo({
              experiment_id: selectedExperiment.value,
              name: authorizedName,
              source_id: sourceId,
              status: '1',
            })
            successStats.experiment.video += 1
          }

          if (authorizeToResource) {
            setStepProgress(index, actionableItems.length, 0.98, `正在创建统一资源视频：${file.name}`)
            await createResourceVideo({
              name: authorizedName,
              source: '2',
              classification: resourceClassification.value,
              knowledge_points: '',
              cover: '',
              source_id: sourceId,
            })
            successStats.resource.video += 1
          }

          progress.value = Math.round(((index + 1) / actionableItems.length) * 100)
          continue
        }

        const uploadedFile = await uploadDocumentFromCase(file.url, file.name, index, actionableItems.length)

        if (type === 'case' && authorizeToExperiment) {
          setStepProgress(index, actionableItems.length, 0.95, `正在创建实验案例原文：${file.name}`)
          await createCase({
            experiment_id: selectedExperiment.value,
            name: authorizedName,
            type: getMimeType(file.name),
            url: uploadedFile.url,
            size: (uploadedFile.file.size / 1024 / 1024).toString(),
            status: '1',
          })
          successStats.experiment.case += 1
        }

        if (type === 'ppt' && authorizeToResource) {
          setStepProgress(index, actionableItems.length, 0.95, `正在创建统一资源课件：${file.name}`)
          await createResourceCourseware({
            name: authorizedName,
            source: '2',
            classification: resourceClassification.value,
            knowledge_points: '',
            url: uploadedFile.url,
            type: getFileExtension(file.name),
            size: `${uploadedFile.file.size}`,
          })
          successStats.resource.courseware += 1
        }

        if (type === 'book') {
          if (authorizeToExperiment) {
            setStepProgress(index, actionableItems.length, 0.95, `正在创建实验案例指导书：${file.name}`)
            await createBook({
              experiment_id: selectedExperiment.value,
              name: authorizedName,
              type: getMimeType(file.name),
              url: uploadedFile.url,
              size: (uploadedFile.file.size / 1024 / 1024).toString(),
              status: '1',
            })
            successStats.experiment.book += 1
          }

          if (authorizeToResource) {
            setStepProgress(index, actionableItems.length, 0.97, `正在创建统一资源教案：${file.name}`)
            await createResourceLessonPlan({
              name: authorizedName,
              source: '2',
              classification: resourceClassification.value,
              knowledge_points: '',
              url: uploadedFile.url,
              type: getFileExtension(file.name),
              size: `${uploadedFile.file.size}`,
            })
            successStats.resource.lessonPlan += 1
          }
        }

        if ((type === 'dataset' || type === 'other') && authorizeToResource) {
          setStepProgress(index, actionableItems.length, 0.95, `正在创建统一资源其他资料：${file.name}`)
          await createResourceOther({
            name: authorizedName,
            source: '2',
            classification: resourceClassification.value,
            knowledge_points: '',
            url: uploadedFile.url,
            type: getFileExtension(file.name),
            size: `${uploadedFile.file.size}`,
          })
          successStats.resource.other += 1
        }

        progress.value = Math.round(((index + 1) / actionableItems.length) * 100)
      }

      const summaryText = buildSummaryText(successStats)
      if (!summaryText) {
        ElMessage.warning('当前授权平台下没有可授权的案例文件')
        return
      }

      ElMessage.success(`授权完成：${summaryText}`)
      progressText.value = `授权完成 ${actionableItems.length}/${actionableItems.length}`
    } catch (error) {
      console.error(error)
      ElMessage.error('批量授权失败')
      progressText.value = '授权失败'
    } finally {
      submitting.value = false
    }
  }

  return {
    caseFileSectionConfig,
    caseFileTypeMap,
    categoryList,
    courses,
    experiments,
    fileSelections,
    groupedFiles,
    list,
    loading,
    platformSelections,
    progress,
    progressText,
    resourceClassification,
    selectedCase,
    selectedCaseId,
    selectedCount,
    selectedCourse,
    selectedExperiment,
    submitting,
    getAllChecked,
    getFileKey,
    getFilesByType,
    handleCaseChange,
    handleToggleAll,
    isTypeSelectable,
    submitAuthorize,
  }
}
