import { onBeforeUnmount } from 'vue'
import {
  getDataProcessPreviewProgress,
  startDataProcessPreview,
} from '@/api/modules/dataProcess'
import type {
  DataProcessPreviewFileBuildProgress,
  DataProcessPreviewProgress,
} from '@/types/dataProcess'

const POLL_INTERVAL_MS = 1500
const MAX_CONSECUTIVE_FAILURES = 3

type PreviewProgressCallback = (progress: DataProcessPreviewProgress) => void

function isActive(progress: DataProcessPreviewProgress) {
  return progress.preview_status === 'queued' || progress.preview_status === 'running'
}

function waitForNextPoll() {
  return new Promise<void>((resolve) => setTimeout(resolve, POLL_INTERVAL_MS))
}

/**
 * 后台切分控制器。
 *
 * startPreviewBuild 只发起一次 POST，随后查询任务级进度；resumePreviewBuild
 * 不重复启动任务，仅接管已有切分。两者都在 completed/failed 时返回最终进度。
 * 响应不依赖逐文件明细，完成后由调用方重新读取预览及源文件统计。
 */
export function useDataProcessPreviewBuild() {
  let activePollRun = 0

  function stopPreviewPolling() {
    activePollRun += 1
  }

  async function pollUntilSettled(
    taskId: string | number,
    initialProgress: DataProcessPreviewProgress,
    pollRun: number,
    onProgress?: PreviewProgressCallback,
  ) {
    let progress = initialProgress
    let consecutiveFailures = 0
    if (pollRun !== activePollRun) return progress
    onProgress?.(progress)

    while (isActive(progress) && pollRun === activePollRun) {
      await waitForNextPoll()
      if (pollRun !== activePollRun) break
      try {
        progress = await getDataProcessPreviewProgress(taskId)
        consecutiveFailures = 0
        onProgress?.(progress)
      } catch (error) {
        consecutiveFailures += 1
        if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) throw error
      }
    }
    return progress
  }

  async function startPreviewBuild(
    taskId: string | number,
    sourceFileIds: Array<string | number>,
    onProgress?: PreviewProgressCallback,
  ): Promise<DataProcessPreviewProgress> {
    stopPreviewPolling()
    const pollRun = activePollRun
    const progress = await startDataProcessPreview(taskId, {
      replace_existing: true,
      source_file_ids: sourceFileIds,
    })
    return pollUntilSettled(taskId, progress, pollRun, onProgress)
  }

  async function resumePreviewBuild(
    taskId: string | number,
    onProgress?: PreviewProgressCallback,
  ): Promise<DataProcessPreviewProgress> {
    stopPreviewPolling()
    const pollRun = activePollRun
    const progress = await getDataProcessPreviewProgress(taskId)
    return pollUntilSettled(taskId, progress, pollRun, onProgress)
  }

  /**
   * 兼容现有上传步骤的逐文件展示契约；底层仍只启动一个后台切分任务。
   * 后端不返回 files[]，因此运行中按任务总进度同步展示，完成后调用方
   * 必须重新加载预览，不能把这里的可视状态当作文件统计来源。
   */
  async function buildPreviewsByFile(
    taskId: string | number,
    sourceFileIds: Array<string | number>,
    onProgress: (progress: DataProcessPreviewFileBuildProgress) => void,
  ): Promise<DataProcessPreviewFileBuildProgress[]> {
    const emitTaskProgress = (taskProgress: DataProcessPreviewProgress) => {
      for (const sourceFileId of sourceFileIds) {
        if (taskProgress.preview_status === 'completed') {
          onProgress({ source_file_id: sourceFileId, status: 'success', progress: 100 })
        } else if (taskProgress.preview_status === 'failed' || taskProgress.preview_status === 'cancelled') {
          onProgress({
            source_file_id: sourceFileId,
            status: 'failed',
            progress: 0,
            error: taskProgress.preview_failure_reason || '切分失败，请重试',
          })
        } else {
          onProgress({
            source_file_id: sourceFileId,
            status: 'processing',
            progress: taskProgress.preview_progress,
          })
        }
      }
    }
    const finalProgress = await startPreviewBuild(taskId, sourceFileIds, emitTaskProgress)
    return sourceFileIds.map((sourceFileId) => (
      finalProgress.preview_status === 'completed'
        ? { source_file_id: sourceFileId, status: 'success', progress: 100 }
        : {
            source_file_id: sourceFileId,
            status: 'failed',
            progress: 0,
            error: finalProgress.preview_failure_reason || '切分失败，请重试',
          }
    ))
  }

  onBeforeUnmount(stopPreviewPolling)

  return {
    startPreviewBuild,
    resumePreviewBuild,
    buildPreviewsByFile,
    stopPreviewPolling,
  }
}
