import { computed, nextTick, ref, type Reactive, type Ref } from 'vue'
import { useRoute } from 'vue-router'
import {
  getDataProcessPreview,
  getDataProcessSourceContent,
  getDataProcessTask,
  regenerateDataProcessTask,
} from '@/api/modules/dataProcess'
import type {
  DataProcessPreviewItem,
  DataProcessRegeneratePayload,
  DataProcessTask,
} from '@/types/dataProcess'
import {
  createStructuredOptionsFromConfig,
  createUnstructuredOptionsFromConfig,
} from './dataProcessCreateState'
import { mapDataProcessSourceFile } from './useDataProcessSourceUpload'
import type {
  PreviewItem,
  ProcessType,
  StructuredProcessOptions,
  UnstructuredProcessOptions,
  UploadedDataFile,
} from './types'

interface ConfirmOptions {
  title: string
  message: string
  confirmText: string
  cancelText: string
  tone: 'warning'
}

interface RegenerationBindings {
  task: Reactive<{ name: string; description: string }>
  processType: Ref<ProcessType>
  structuredOptions: Ref<StructuredProcessOptions>
  unstructuredOptions: Ref<UnstructuredProcessOptions>
  uploadedFiles: Ref<UploadedDataFile[]>
  previewItems: Ref<PreviewItem[]>
  selectedPreviewFileId: Ref<string | null>
  selectedPreviewId: Ref<string | null>
  selectedPreviewIdsByFile: Ref<Record<string, string>>
  previewSignature: Ref<string>
  dirty: Ref<boolean>
  buildPreviewConfigSignature: () => string
  buildPreviewSignature: () => string
  mapPreviewItem: (item: DataProcessPreviewItem) => PreviewItem
  resetDownstream: () => void
}

async function loadSourceContent(taskId: string, fileId: string | number) {
  const chunks: string[] = []
  let startLine = 1
  while (true) {
    const source = await getDataProcessSourceContent(taskId, fileId, {
      start_line: startLine,
      line_count: 10_000,
    })
    chunks.push(source.content || '')
    if (!source.has_more) break
    const nextLine = Number(source.end_line || startLine) + 1
    if (nextLine <= startLine) break
    startLine = nextLine
  }
  // source_content_lines 已保留原始换行；分页之间直接拼接，避免凭空增加空行并破坏偏移。
  return chunks.join('')
}

async function loadAllPreviews(taskId: string, mapPreviewItem: RegenerationBindings['mapPreviewItem']) {
  const first = await getDataProcessPreview(taskId, { page: 1, page_size: 500 })
  const items = [...first.items]
  const pages = Math.ceil(first.total / first.page_size)
  for (let page = 2; page <= pages; page += 1) {
    const next = await getDataProcessPreview(taskId, { page, page_size: 500 })
    items.push(...next.items)
  }
  return items.map(mapPreviewItem)
}

export function useDataProcessRegeneration(bindings: RegenerationBindings) {
  const route = useRoute()
  const isRegeneration = computed(() => route.name === 'data-process-regenerate')
  const isWorkflowResume = computed(() => route.name === 'data-process-workflow')
  const sourceTaskId = computed(() => (
    isRegeneration.value || isWorkflowResume.value ? String(route.params.id || '') : ''
  ))
  const originalProcessType = ref<ProcessType | null>(null)
  const originalTaskUpdatedAt = ref('')
  const regenerationPrepared = ref(false)
  const originalPreviewConfigSignature = ref('')
  const confirmedPreviewConfigSignature = ref('')
  const hydrating = ref(false)
  const initializationError = ref('')

  async function hydrateWorkspace(task: DataProcessTask, preservePreviews: boolean) {
    const taskId = String(task.id)
    bindings.uploadedFiles.value = await Promise.all((task.source_files || []).map(async (file) => (
      mapDataProcessSourceFile(file, await loadSourceContent(taskId, file.id))
    )))
    bindings.previewItems.value = preservePreviews
      ? await loadAllPreviews(taskId, bindings.mapPreviewItem)
      : []

    const configSignature = bindings.buildPreviewConfigSignature()
    const previewCounts = new Map<string, number>()
    for (const item of bindings.previewItems.value) {
      previewCounts.set(item.sourceFileId, (previewCounts.get(item.sourceFileId) || 0) + 1)
    }
    for (const file of bindings.uploadedFiles.value) {
      const count = previewCounts.get(String(file.sourceFileId)) || 0
      file.previewCount = count
      file.previewStatus = preservePreviews && count > 0 ? 'success' : 'waiting'
      file.previewProgress = preservePreviews && count > 0 ? 100 : 0
      file.previewConfigSignature = preservePreviews && count > 0 ? configSignature : undefined
    }

    bindings.selectedPreviewFileId.value = String(bindings.uploadedFiles.value[0]?.uid ?? '') || null
    bindings.selectedPreviewId.value = bindings.selectedPreviewFileId.value
      ? bindings.previewItems.value.find((item) => (
          item.sourceFileId === bindings.selectedPreviewFileId.value
        ))?.id ?? null
      : null
    bindings.selectedPreviewIdsByFile.value = (
      bindings.selectedPreviewFileId.value && bindings.selectedPreviewId.value
    ) ? { [bindings.selectedPreviewFileId.value]: bindings.selectedPreviewId.value } : {}
    bindings.previewSignature.value = preservePreviews && bindings.previewItems.value.length
      ? bindings.buildPreviewSignature()
      : ''
    bindings.resetDownstream()
  }

  async function loadSource() {
    if (!sourceTaskId.value) return
    hydrating.value = true
    initializationError.value = ''
    try {
      const sourceTask = await getDataProcessTask(sourceTaskId.value)
      const sourceType = sourceTask.process_type as ProcessType
      originalProcessType.value = isRegeneration.value ? sourceType : null
      originalTaskUpdatedAt.value = sourceTask.updated_at
      bindings.task.name = sourceTask.name
      bindings.task.description = sourceTask.description || ''
      bindings.processType.value = sourceType
      const config = sourceTask.config || {}
      bindings.structuredOptions.value = createStructuredOptionsFromConfig(config)
      bindings.unstructuredOptions.value = createUnstructuredOptionsFromConfig(config)
      originalPreviewConfigSignature.value = bindings.buildPreviewConfigSignature()
      confirmedPreviewConfigSignature.value = ''
      await hydrateWorkspace(sourceTask, true)
      await nextTick()
      bindings.dirty.value = false
      return sourceTask
    } catch (error) {
      initializationError.value = error instanceof Error
        ? error.message
        : '原数据处理任务加载失败，请返回详情页后重试'
    } finally {
      hydrating.value = false
    }
  }

  async function confirmPreviewConfigChange(
    openConfirm: (options: ConfirmOptions) => Promise<boolean | undefined>,
  ) {
    if (!isRegeneration.value) return true
    if (!bindings.previewItems.value.length) return true
    const currentSignature = bindings.buildPreviewConfigSignature()
    const changed = currentSignature !== originalPreviewConfigSignature.value
    if (!changed || currentSignature === confirmedPreviewConfigSignature.value) return true
    const confirmed = await openConfirm({
      title: '确认修改切分配置？',
      message: '修改预处理或切分配置后，将按新配置重新切分。在点击“开始生成”前，原生成结果和已发布数据会继续保留。',
      confirmText: '确认并继续',
      cancelText: '返回检查',
      tone: 'warning',
    })
    if (confirmed) confirmedPreviewConfigSignature.value = currentSignature
    return Boolean(confirmed)
  }

  async function prepareRegeneration(
    payload: Omit<DataProcessRegeneratePayload, 'expected_updated_at'>,
  ) {
    // 第一次 prepare 后，上传、切分、编辑预览和生成都会推进任务版本。
    // 再次提交前读取同一任务的最新版本，仍由后端事务处理读取后的并发竞争。
    if (regenerationPrepared.value) {
      const latestTask = await getDataProcessTask(sourceTaskId.value)
      originalTaskUpdatedAt.value = latestTask.updated_at || originalTaskUpdatedAt.value
    }
    const regenerated = await regenerateDataProcessTask(sourceTaskId.value, {
      ...payload,
      expected_updated_at: originalTaskUpdatedAt.value,
    })
    originalTaskUpdatedAt.value = regenerated.task.updated_at || originalTaskUpdatedAt.value
    originalPreviewConfigSignature.value = bindings.buildPreviewConfigSignature()
    confirmedPreviewConfigSignature.value = ''
    regenerationPrepared.value = true
    bindings.dirty.value = true
    try {
      const regeneratedTask = regenerated.task.source_files
        ? regenerated.task
        : await getDataProcessTask(regenerated.task.id)
      originalTaskUpdatedAt.value = regeneratedTask.updated_at || originalTaskUpdatedAt.value
      hydrating.value = true
      try {
        await hydrateWorkspace(regeneratedTask, !regenerated.preview_invalidated)
      } finally {
        hydrating.value = false
      }
    } catch (error) {
      initializationError.value = error instanceof Error
        ? `重新生成配置已保存，但工作区恢复失败：${error.message}`
        : '重新生成配置已保存，但工作区恢复失败，请重试加载原任务'
      throw error
    }
    return regenerated
  }

  async function confirmStartGeneration(
    openConfirm: (options: ConfirmOptions) => Promise<boolean | undefined>,
    syncPreviewChanges: () => Promise<void>,
  ) {
    if (isRegeneration.value) {
      const confirmed = await openConfirm({
        title: '开始重新生成？',
        message: '点击开始后，当前生成结果将被替换。已发布数据集会继续保留，直到重新发布。',
        confirmText: '开始生成',
        cancelText: '继续检查',
        tone: 'warning',
      })
      if (!confirmed) return false
    }
    await syncPreviewChanges()
    return true
  }

  return {
    sourceTaskId,
    isRegeneration,
    isWorkflowResume,
    originalProcessType,
    originalTaskUpdatedAt,
    regenerationPrepared,
    hydrating,
    initializationError,
    hydrateWorkspace,
    loadSource,
    confirmPreviewConfigChange,
    prepareRegeneration,
    confirmStartGeneration,
  }
}
