import {
  createExpenseClaimItem,
  uploadExpenseClaimItemAttachment
} from '../../services/reimbursements.js'
import {
  formatCurrency,
  isSystemGeneratedExpenseItemSource,
  normalizeIsoDateValue
} from './travelRequestDetailExpenseModel.js'

const SMART_ENTRY_RECOGNITION_TASK_RETENTION_MS = 10 * 60 * 1000
const smartEntryRecognitionTasks = new Map()
let smartEntryRecognitionTaskSeq = 0

function normalizeSmartEntryClaimId(claimId) {
  return String(claimId || '').trim()
}

export function buildRecognizedExpenseItemPatch(payload, fileName = '') {
  const recognizedItemAmount = Number(payload?.item_amount ?? payload?.itemAmount)
  const recognizedItemDate = normalizeIsoDateValue(payload?.item_date ?? payload?.itemDate)
  const recognizedItemType = String(payload?.item_type ?? payload?.itemType ?? '').trim()
  const recognizedItemReason = String(payload?.item_reason ?? payload?.itemReason ?? '').trim()
  const recognizedItemLocation = String(payload?.item_location ?? payload?.itemLocation ?? '').trim()
  const itemPatch = {
    invoiceId: String(payload?.invoice_id || '').trim(),
    attachmentHint: String(payload?.attachment?.file_name || fileName || '').trim()
  }
  if (recognizedItemDate) {
    itemPatch.itemDate = recognizedItemDate
  }
  if (recognizedItemType) {
    itemPatch.itemType = recognizedItemType
  }
  if (recognizedItemReason) {
    itemPatch.itemReason = recognizedItemReason
  }
  if (recognizedItemLocation) {
    itemPatch.itemLocation = recognizedItemLocation
  }
  if (Number.isFinite(recognizedItemAmount) && recognizedItemAmount > 0) {
    itemPatch.itemAmount = recognizedItemAmount
    itemPatch.amount = formatCurrency(recognizedItemAmount)
  }
  return itemPatch
}

function buildSmartEntryRecognitionSnapshot(task) {
  if (!task) {
    return null
  }

  return {
    id: task.id,
    claimId: task.claimId,
    busy: task.busy,
    total: task.total,
    current: task.current,
    completed: task.completed,
    successCount: task.successCount,
    failedCount: task.failedCount,
    uploadingItemId: task.uploadingItemId,
    fileName: task.fileName,
    status: task.status,
    payloads: [...task.payloads],
    errors: [...task.errors]
  }
}

function notifySmartEntryRecognitionTask(task) {
  const snapshot = buildSmartEntryRecognitionSnapshot(task)
  task.listeners.forEach((listener) => {
    try {
      listener(snapshot)
    } catch (error) {
      console.error('同步附件识别状态失败', error)
    }
  })
}

function scheduleSmartEntryRecognitionTaskCleanup(task) {
  if (task.cleanupTimer) {
    clearTimeout(task.cleanupTimer)
  }
  task.cleanupTimer = globalThis.setTimeout(() => {
    const currentTask = smartEntryRecognitionTasks.get(task.claimId)
    if (currentTask?.id === task.id && !currentTask.busy) {
      smartEntryRecognitionTasks.delete(task.claimId)
    }
  }, SMART_ENTRY_RECOGNITION_TASK_RETENTION_MS)
}

function getSmartEntryRecognitionTask(claimId) {
  return smartEntryRecognitionTasks.get(normalizeSmartEntryClaimId(claimId)) || null
}

export function subscribeSmartEntryRecognitionTask(claimId, listener) {
  const task = getSmartEntryRecognitionTask(claimId)
  if (!task) {
    listener(null)
    return () => {}
  }

  task.listeners.add(listener)
  listener(buildSmartEntryRecognitionSnapshot(task))
  return () => {
    task.listeners.delete(listener)
  }
}

function resolveSmartEntryTaskAvailableItems(itemSnapshots) {
  return (Array.isArray(itemSnapshots) ? itemSnapshots : [])
    .filter((item) => item && !isSystemGeneratedExpenseItemSource(item) && !item.invoiceId)
    .map((item) => ({ id: String(item.id || '').trim() }))
    .filter((item) => item.id)
}

export function resolveCreatedSmartEntryRecognitionItem(items = [], knownItemIds = new Set()) {
  return (Array.isArray(items) ? items : []).find((entry) => {
    const itemId = String(entry?.id || '').trim()
    const invoiceId = String(entry?.invoiceId || entry?.invoice_id || '').trim()
    return (
      itemId
      && !knownItemIds.has(itemId)
      && !invoiceId
      && !isSystemGeneratedExpenseItemSource(entry)
    )
  }) || null
}

async function resolveSmartEntryRecognitionTaskItem(task) {
  const availableItem = task.availableItems.shift()
  if (availableItem?.id) {
    return { id: availableItem.id, createdItem: null }
  }

  const claim = await createExpenseClaimItem(task.claimId, {})
  const items = Array.isArray(claim?.items) ? claim.items : []
  const createdItem = resolveCreatedSmartEntryRecognitionItem(items, task.knownItemIds)

  if (!createdItem) {
    throw new Error('新增费用明细失败，请稍后重试。')
  }

  const itemId = String(createdItem.id || '').trim()
  task.knownItemIds.add(itemId)
  return { id: itemId, createdItem }
}

async function runSmartEntryRecognitionTask(task, files) {
  notifySmartEntryRecognitionTask(task)

  for (let index = 0; index < files.length; index += 1) {
    const file = files[index]
    const fileName = String(file?.name || `第 ${index + 1} 张附件`).trim()
    task.current = index + 1
    task.fileName = fileName
    task.uploadingItemId = ''
    notifySmartEntryRecognitionTask(task)

    try {
      const targetItem = await resolveSmartEntryRecognitionTaskItem(task)
      task.uploadingItemId = targetItem.id
      notifySmartEntryRecognitionTask(task)

      const payload = await uploadExpenseClaimItemAttachment(task.claimId, targetItem.id, file)
      task.successCount += 1
      task.payloads.push({
        id: `${task.id}:${index}:${targetItem.id}`,
        itemId: targetItem.id,
        fileName,
        payload,
        createdItem: targetItem.createdItem
      })
    } catch (error) {
      task.failedCount += 1
      task.errors.push({
        fileName,
        message: error?.message || '附件识别失败，请稍后重试。'
      })
    } finally {
      task.completed = index + 1
      task.uploadingItemId = ''
      notifySmartEntryRecognitionTask(task)
    }
  }

  task.busy = false
  task.current = task.total
  task.fileName = ''
  task.status = task.failedCount
    ? task.successCount
      ? 'partial'
      : 'failed'
    : 'completed'
  notifySmartEntryRecognitionTask(task)
  scheduleSmartEntryRecognitionTaskCleanup(task)
}

export function startSmartEntryRecognitionTask({ claimId, files, itemSnapshots }) {
  const normalizedClaimId = normalizeSmartEntryClaimId(claimId)
  const pendingFiles = Array.isArray(files) ? files.filter(Boolean) : []
  if (!normalizedClaimId || !pendingFiles.length) {
    return { task: null, reused: false }
  }

  const existingTask = getSmartEntryRecognitionTask(normalizedClaimId)
  if (existingTask?.busy) {
    return { task: existingTask, reused: true }
  }

  const sourceItems = Array.isArray(itemSnapshots) ? itemSnapshots : []
  const task = {
    id: `smart-entry-${Date.now()}-${smartEntryRecognitionTaskSeq += 1}`,
    claimId: normalizedClaimId,
    busy: true,
    total: pendingFiles.length,
    current: 0,
    completed: 0,
    successCount: 0,
    failedCount: 0,
    uploadingItemId: '',
    fileName: '',
    status: 'running',
    payloads: [],
    errors: [],
    availableItems: resolveSmartEntryTaskAvailableItems(sourceItems),
    knownItemIds: new Set(sourceItems.map((item) => String(item?.id || '').trim()).filter(Boolean)),
    listeners: new Set(),
    cleanupTimer: null
  }

  smartEntryRecognitionTasks.set(normalizedClaimId, task)
  void runSmartEntryRecognitionTask(task, pendingFiles)
  return { task, reused: false }
}
