import { isApplicationDocumentNo } from '../../utils/documentClassification.js'

export const EXPENSE_TYPE_OPTIONS = [
  { value: 'travel', label: '差旅费' },
  { value: 'train_ticket', label: '火车票' },
  { value: 'flight_ticket', label: '机票' },
  { value: 'ship_ticket', label: '轮船票' },
  { value: 'ferry_ticket', label: '轮船票' },
  { value: 'hotel_ticket', label: '住宿票' },
  { value: 'ride_ticket', label: '乘车' },
  { value: 'office', label: '办公用品费' },
  { value: 'meeting', label: '会务费' },
  { value: 'training', label: '培训费' },
  { value: 'hotel', label: '住宿费' },
  { value: 'transport', label: '交通费' },
  { value: 'meal', label: '业务招待费' },
  { value: 'travel_allowance', label: '出差补贴' },
  { value: 'other', label: '其他费用' }
]

const LEGACY_EXPENSE_TYPE_LABELS = {
  entertainment: '业务招待费'
}

export const LOCATION_REQUIRED_EXPENSE_TYPES = new Set([
  'travel',
  'meeting',
  'entertainment'
])

export const SYSTEM_GENERATED_EXPENSE_TYPES = new Set(['travel_allowance'])
export const OPTIONAL_ATTACHMENT_EXPENSE_TYPES = new Set(['ride_ticket', 'travel_allowance'])
export const LONG_DISTANCE_TRAVEL_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket'])
export const ROUTE_DESCRIPTION_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket', 'ship_ticket', 'ferry_ticket', 'ride_ticket'])
export const HOTEL_DESCRIPTION_EXPENSE_TYPES = new Set(['hotel_ticket'])
export const ROUTE_DESCRIPTION_PATTERN = /^[A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40}\s*-\s*[A-Za-z0-9\u4e00-\u9fa5（）()·]{2,40}$/
export const STANDARD_ADJUSTMENT_RISK_SOURCE = 'reimbursement_standard_adjustment'

export function parseCurrency(value) {
  return Number.parseFloat(String(value).replace(/[^\d.]/g, '')) || 0
}

function parseOptionalCurrency(value) {
  if (value === null || value === undefined || String(value).trim() === '') {
    return null
  }
  const normalized = String(value).replace(/[^\d.]/g, '')
  if (!normalized) {
    return null
  }
  const amount = Number.parseFloat(normalized)
  return Number.isFinite(amount) && amount >= 0 ? amount : null
}

export function formatCurrency(value) {
  return new Intl.NumberFormat('zh-CN', {
    style: 'currency',
    currency: 'CNY',
    minimumFractionDigits: 0,
    maximumFractionDigits: Number.isInteger(value) ? 0 : 2
  }).format(value)
}

export function normalizeExpenseType(value) {
  return String(value || '').trim() || 'other'
}

export function isApplicationDocumentRequest(request) {
  const documentType = String(
    request?.documentTypeCode
    || request?.document_type_code
    || request?.documentType
    || request?.document_type
    || ''
  ).trim()
  const claimNo = String(
    request?.claimNo
    || request?.claim_no
    || request?.documentNo
    || request?.id
    || ''
  ).trim().toUpperCase()
  const typeCode = normalizeExpenseType(request?.typeCode || request?.expense_type)

  return (
    documentType === 'application'
    || documentType === 'expense_application'
    || isApplicationDocumentNo(claimNo)
    || typeCode === 'application'
    || typeCode.endsWith('_application')
  )
}

export function resolveExpenseTypeLabel(value) {
  const normalized = normalizeExpenseType(value)
  return EXPENSE_TYPE_OPTIONS.find((option) => option.value === normalized)?.label
    || LEGACY_EXPENSE_TYPE_LABELS[normalized]
    || '其他费用'
}

export function isSystemGeneratedExpenseItemSource(source) {
  const itemType = normalizeExpenseType(source?.itemType || source?.item_type)
  return Boolean(source?.isSystemGenerated || source?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType))
}

export function isAttachmentRequiredExpenseItem(source) {
  const itemType = normalizeExpenseType(source?.itemType || source?.item_type)
  return !isSystemGeneratedExpenseItemSource({ ...source, itemType }) && !OPTIONAL_ATTACHMENT_EXPENSE_TYPES.has(itemType)
}

export function hasUploadedReceiptReference(source) {
  const invoiceId = String(source?.invoiceId ?? source?.invoice_id ?? '').trim()
  if (!isPlaceholderValue(invoiceId)) {
    return true
  }
  return Array.isArray(source?.attachments) && source.attachments.some((item) => !isPlaceholderValue(item))
}

export function isIgnorableExpenseDraftPlaceholder(item) {
  if (!item || isSystemGeneratedExpenseItemSource(item) || hasUploadedReceiptReference(item)) {
    return false
  }
  const amount = Number(item?.itemAmount ?? item?.item_amount ?? 0)
  const missingAmount = !Number.isFinite(amount) || amount <= 0
  const missingReason = isPlaceholderValue(item?.itemReason ?? item?.item_reason)
  const missingLocation = isPlaceholderValue(item?.itemLocation ?? item?.item_location)
  return missingAmount && missingReason && missingLocation
}

export function isLocationRequiredExpenseType(value) {
  return LOCATION_REQUIRED_EXPENSE_TYPES.has(normalizeExpenseType(value))
}

export function resolveLocationSummaryLabel(value) {
  return isLocationRequiredExpenseType(value) ? '业务地点' : '采购/收货地点'
}

export function isRouteDescriptionExpenseType(value) {
  return ROUTE_DESCRIPTION_EXPENSE_TYPES.has(normalizeExpenseType(value))
}

export function isHotelDescriptionExpenseType(value) {
  return HOTEL_DESCRIPTION_EXPENSE_TYPES.has(normalizeExpenseType(value))
}

export function resolveExpenseDetailHint(expenseType) {
  if (isRouteDescriptionExpenseType(expenseType)) {
    return '起始地-目的地'
  }
  if (isHotelDescriptionExpenseType(expenseType)) {
    return '目的地酒店'
  }
  if (!isLocationRequiredExpenseType(expenseType)) {
    return '非必填'
  }
  return '待补充'
}

export function resolveLocationDisplay(value, expenseType) {
  return isPlaceholderValue(value) ? resolveExpenseDetailHint(expenseType) : value
}

export function isSyntheticLocationDisplay(value, expenseType) {
  const text = String(value || '').trim()
  return ['待补充', '非必填', resolveExpenseDetailHint(expenseType)].includes(text)
}

export function isValidRouteDescription(value) {
  const text = String(value || '').trim()
  return ROUTE_DESCRIPTION_PATTERN.test(text) && !/\d{4}[-/年.]\d{1,2}[-/月.]\d{1,2}/.test(text)
}

export function resolveExpenseReasonPlaceholder(itemType) {
  if (isRouteDescriptionExpenseType(itemType)) {
    return '起始地-目的地，例如：广州南-北京南'
  }
  if (isHotelDescriptionExpenseType(itemType)) {
    return '目的地酒店，例如：北京中心酒店'
  }
  return '输入费用说明'
}

export function resolveExpenseReasonHelper(itemType) {
  if (isRouteDescriptionExpenseType(itemType)) {
    return '起始地-目的地'
  }
  if (isHotelDescriptionExpenseType(itemType)) {
    return '目的地酒店'
  }
  return '业务报销说明'
}

export function resolveExpenseDescriptionDetail(itemType, itemLocation) {
  if (isRouteDescriptionExpenseType(itemType) || isHotelDescriptionExpenseType(itemType)) {
    return resolveExpenseReasonHelper(itemType)
  }
  return resolveLocationDisplay(itemLocation, itemType)
}

export function buildFallbackProgressSteps(requestModel = {}) {
  const node = String(requestModel?.node || requestModel?.workflowNode || requestModel?.approvalStage || '').trim()
  const approvalKey = String(requestModel?.approvalKey || '').trim()
  const pendingPayment = approvalKey === 'pending_payment' || /待付款/.test(node)
  const paid = /已付款/.test(node)
  const completed = approvalKey === 'completed' || paid || /审批完成|申请完成|已完成/.test(node)
  const archived = /申请归档|已归档/.test(node)
  const hasRelatedApplication = Boolean(requestModel?.relatedApplication?.claimNo)

  if (isApplicationDocumentRequest(requestModel)) {
    const inLeaderApproval = approvalKey === 'in_progress' || /直属领导|领导审批|审批中/.test(node)

    return [
      {
        index: 1,
        label: '创建申请',
        time: completed || inLeaderApproval ? '已完成' : '进行中',
        done: completed || inLeaderApproval,
        active: true,
        current: !(completed || inLeaderApproval)
      },
      {
        index: 2,
        label: '直属领导审批',
        time: completed ? '已完成' : inLeaderApproval ? '进行中' : '待处理',
        done: completed,
        active: completed || inLeaderApproval,
        current: !completed && inLeaderApproval
      },
      {
        index: 3,
        label: '关联单据状态',
        time: hasRelatedApplication ? '已关联' : completed ? '未关联' : '待处理',
        done: archived,
        active: completed || archived,
        current: completed && !archived
      },
      {
        index: 4,
        label: '已归档',
        time: archived ? '已完成' : '待处理',
        done: archived,
        active: archived,
        current: archived
      }
    ]
  }

  return [
    { index: 1, label: '关联单据', time: hasRelatedApplication ? '已关联' : '待核对', done: hasRelatedApplication, active: true, current: !hasRelatedApplication },
    { index: 2, label: '待提交', time: hasRelatedApplication ? '进行中' : '待处理', active: hasRelatedApplication, current: hasRelatedApplication },
    { index: 3, label: '直属领导审批', time: '待处理' },
    { index: 4, label: '财务审批', time: '待处理' },
    { index: 5, label: '待付款', time: pendingPayment ? '进行中' : completed ? '已完成' : '待处理', done: completed, active: pendingPayment || completed, current: pendingPayment },
    { index: 6, label: '已付款', time: paid || completed ? '已完成' : '待处理', done: paid || completed, active: paid || completed, current: false },
    { index: 7, label: '已归档', time: paid || completed ? '已完成' : '待处理', done: paid || completed, active: paid || completed, current: false }
  ]
}

export function buildFallbackExpenseItems(request) {
  if (isApplicationDocumentRequest(request)) {
    return []
  }

  return [
    buildExpenseItemViewModel({
      id: 'fallback-1',
      itemDate: '',
      itemType: request.typeCode || 'other',
      itemReason: request.reason,
      itemLocation: request.sceneTarget,
      itemAmount: parseCurrency(request.amountDisplay),
      invoiceId: '',
      time: '待补充',
      dayLabel: request.detailVariant === 'travel' ? '出行日' : '业务发生日',
      name: request.typeLabel,
      category: request.typeLabel,
      desc: request.reason,
      detail: resolveLocationDisplay(request.sceneTarget, request.typeCode),
      amount: request.amountDisplay,
      status: '待补充',
      tone: 'bad',
      attachmentStatus: '待上传',
      attachmentHint: '请在此单据中继续补充附件',
      attachmentTone: 'missing',
      attachments: [],
      riskLabel: '待补材料',
      riskText: request.riskSummary,
      riskTone: 'medium'
    }, 0, request)
  ]
}

export function isPlaceholderValue(value) {
  const text = String(value || '').trim()
  if (!text) {
    return true
  }

  return ['待补充', '暂无', '无', '未知', '处理中'].includes(text.replace(/\s+/g, ''))
}

export function normalizeDetailNoteDraftValue(value) {
  const text = String(value || '').trim()
  return isPlaceholderValue(text) ? '' : text
}

export function isValidIsoDate(value) {
  const normalized = String(value || '').trim()
  if (!/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
    return false
  }

  const [yearText, monthText, dayText] = normalized.split('-')
  const year = Number(yearText)
  const month = Number(monthText)
  const day = Number(dayText)

  if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {
    return false
  }

  const candidate = new Date(Date.UTC(year, month - 1, day))
  return (
    candidate.getUTCFullYear() === year &&
    candidate.getUTCMonth() === month - 1 &&
    candidate.getUTCDate() === day
  )
}

export function normalizeIsoDateValue(value) {
  const normalized = String(value || '').trim()
  if (isValidIsoDate(normalized)) {
    return normalized
  }

  const match = normalized.match(/^(\d{4}-\d{2}-\d{2})/)
  if (match && isValidIsoDate(match[1])) {
    return match[1]
  }

  const candidate = value instanceof Date ? value : new Date(normalized)
  if (Number.isNaN(candidate.getTime())) {
    return ''
  }

  const year = candidate.getFullYear()
  const month = String(candidate.getMonth() + 1).padStart(2, '0')
  const day = String(candidate.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

export function formatExpenseFilledTime(value) {
  const normalized = String(value || '').trim()
  if (!normalized) {
    return ''
  }

  const candidate = value instanceof Date ? value : new Date(normalized)
  if (Number.isNaN(candidate.getTime())) {
    return normalized
  }

  const year = candidate.getFullYear()
  const month = String(candidate.getMonth() + 1).padStart(2, '0')
  const day = String(candidate.getDate()).padStart(2, '0')
  const hours = String(candidate.getHours()).padStart(2, '0')
  const minutes = String(candidate.getMinutes()).padStart(2, '0')
  return `${year}-${month}-${day} ${hours}:${minutes}`
}

export function resolveExpenseUploadHint(value) {
  const normalized = String(value || '').trim()
  return normalized || '仅支持上传 1 张 JPG、PNG、PDF 单据'
}

export function extractAttachmentDisplayName(value) {
  const normalized = String(value || '').trim()
  if (!normalized) {
    return ''
  }

  return normalized.split('/').filter(Boolean).pop() || normalized
}

export function resolveExpenseItemViewId(source, index, requestModel) {
  return String(source?.id || `${requestModel?.claimId || requestModel?.id || 'claim'}-item-${index}`)
}

export function buildTravelTimeLabelMap(items, requestModel) {
  const travelItems = items
    .map((item, index) => {
      const itemType = normalizeExpenseType(item?.itemType || item?.item_type || requestModel?.typeCode || 'other')
      return {
        id: resolveExpenseItemViewId(item, index, requestModel),
        index,
        itemType,
        itemDate: normalizeIsoDateValue(item?.itemDate ?? item?.item_date),
        isSystemGenerated: isSystemGeneratedExpenseItemSource({ ...item, itemType })
      }
    })
    .filter((item) => !item.isSystemGenerated && LONG_DISTANCE_TRAVEL_EXPENSE_TYPES.has(item.itemType))
    .sort((left, right) => {
      const dateCompare = String(left.itemDate || '').localeCompare(String(right.itemDate || ''))
      return dateCompare || left.index - right.index
    })

  const labels = new Map()
  if (!travelItems.length) {
    return labels
  }

  travelItems.forEach((item, index) => {
    if (index === 0) {
      labels.set(item.id, '出发时间')
    } else if (index === travelItems.length - 1) {
      labels.set(item.id, '返回时间')
    } else {
      labels.set(item.id, '中转时间')
    }
  })
  return labels
}

export function resolveExpenseTimeLabel({ id, itemType, isSystemGenerated, requestModel, travelTimeLabelMap }) {
  if (isSystemGenerated) {
    return '系统自动计算'
  }
  if (travelTimeLabelMap?.has(id)) {
    return travelTimeLabelMap.get(id)
  }
  if (itemType === 'ride_ticket') {
    return '乘车时间'
  }
  if (itemType === 'hotel_ticket') {
    return '住宿时间'
  }
  return requestModel?.detailVariant === 'travel' ? '出行时间' : '业务发生时间'
}

export function buildStandardAdjustmentMap(requestModel = {}) {
  const flags = Array.isArray(requestModel?.riskFlags)
    ? requestModel.riskFlags
    : Array.isArray(requestModel?.risk_flags_json)
      ? requestModel.risk_flags_json
      : []
  const adjustmentMap = new Map()

  flags.forEach((flag) => {
    if (!flag || typeof flag !== 'object') {
      return
    }
    if (String(flag.source || '').trim() !== STANDARD_ADJUSTMENT_RISK_SOURCE) {
      return
    }
    const itemId = String(flag.item_id || flag.itemId || '').trim()
    if (!itemId) {
      return
    }
    const originalAmount = parseOptionalCurrency(flag.original_amount ?? flag.originalAmount)
    const reimbursableAmount = parseOptionalCurrency(flag.reimbursable_amount ?? flag.reimbursableAmount)
    if (reimbursableAmount === null) {
      return
    }
    const employeeAbsorbedAmount = parseOptionalCurrency(flag.employee_absorbed_amount ?? flag.employeeAbsorbedAmount) || 0
    adjustmentMap.set(itemId, {
      originalAmount,
      reimbursableAmount,
      employeeAbsorbedAmount,
      message: String(flag.message || flag.summary || '').trim()
    })
  })

  return adjustmentMap
}

function resolveSourceStandardAdjustment(source, id, requestModel) {
  const requestAdjustment = buildStandardAdjustmentMap(requestModel).get(id)
  if (requestAdjustment) {
    return requestAdjustment
  }

  const reimbursableAmount = parseOptionalCurrency(source?.reimbursableAmount ?? source?.reimbursable_amount)
  if (reimbursableAmount === null) {
    return null
  }
  const originalAmount = parseOptionalCurrency(
    source?.originalItemAmount
    ?? source?.original_item_amount
    ?? source?.originalAmount
    ?? source?.original_amount
  )
  const employeeAbsorbedAmount = parseOptionalCurrency(
    source?.employeeAbsorbedAmount
    ?? source?.employee_absorbed_amount
  ) || 0
  const hasExplicitAdjustmentMarker = Boolean(
    source?.standardAdjustmentAccepted
    || source?.standard_adjustment_accepted
    || source?.hasStandardAdjustment
    || source?.has_standard_adjustment
    || String(source?.standardAdjustmentMessage || source?.standard_adjustment_message || '').trim()
    || employeeAbsorbedAmount > 0
    || (originalAmount !== null && reimbursableAmount < originalAmount)
  )
  if (!hasExplicitAdjustmentMarker) {
    return null
  }

  return {
    originalAmount,
    reimbursableAmount,
    employeeAbsorbedAmount,
    message: String(source?.standardAdjustmentMessage || source?.standard_adjustment_message || '').trim()
  }
}

export function buildExpenseItemViewModel(source, index, requestModel, travelTimeLabelMap = new Map()) {
  const itemType = normalizeExpenseType(source?.itemType || source?.item_type || requestModel?.typeCode || 'other')
  const isSystemGenerated = isSystemGeneratedExpenseItemSource({ ...source, itemType })
  const id = resolveExpenseItemViewId(source, index, requestModel)
  const itemReason = String(source?.itemReason ?? source?.item_reason ?? '').trim()
  const itemLocation = String(source?.itemLocation ?? source?.item_location ?? '').trim()
  const itemNote = String(source?.itemNote ?? source?.item_note ?? '').trim()
  const itemDate = normalizeIsoDateValue(source?.itemDate ?? source?.item_date)
  const itemAmount = parseCurrency(source?.itemAmount ?? source?.item_amount)
  const invoiceId = String(source?.invoiceId ?? source?.invoice_id ?? '').trim()
  const attachmentName = String(source?.attachmentName || source?.attachment_name || extractAttachmentDisplayName(invoiceId)).trim()
  const attachments = invoiceId ? [attachmentName || invoiceId] : []
  const standardAdjustment = resolveSourceStandardAdjustment(source, id, requestModel)
  const originalItemAmount = standardAdjustment?.originalAmount ?? itemAmount
  const reimbursableAmount = standardAdjustment?.reimbursableAmount ?? itemAmount
  const employeeAbsorbedAmount = standardAdjustment?.employeeAbsorbedAmount || Math.max(originalItemAmount - reimbursableAmount, 0)
  const hasStandardAdjustment = reimbursableAmount >= 0 && reimbursableAmount < originalItemAmount
  const amountDisplay = itemAmount > 0 ? formatCurrency(itemAmount) : '待补充'
  const reimbursableAmountDisplay = reimbursableAmount > 0 ? formatCurrency(reimbursableAmount) : '待补充'
  const riskText = String(source?.riskText || '').trim()
  const filledAt = formatExpenseFilledTime(
    source?.filledAt
    || source?.filled_at
    || source?.createdAt
    || source?.created_at
  )

  return {
    id,
    itemDate,
    itemType,
    itemReason,
    itemLocation,
    itemNote,
    itemAmount,
    originalItemAmount,
    originalAmountDisplay: originalItemAmount > 0 ? formatCurrency(originalItemAmount) : amountDisplay,
    reimbursableAmount,
    reimbursableAmountDisplay,
    employeeAbsorbedAmount,
    employeeAbsorbedAmountDisplay: employeeAbsorbedAmount > 0 ? formatCurrency(employeeAbsorbedAmount) : '',
    hasStandardAdjustment,
    standardAdjustmentAccepted: Boolean(standardAdjustment),
    standardAdjustmentMessage: standardAdjustment?.message || '',
    invoiceId,
    isSystemGenerated,
    time: itemDate || '待补充',
    filledAt: filledAt || '待同步',
    dayLabel: resolveExpenseTimeLabel({
      id,
      itemType,
      isSystemGenerated,
      requestModel,
      travelTimeLabelMap
    }),
    name: resolveExpenseTypeLabel(itemType),
    category: resolveExpenseTypeLabel(itemType),
    desc: itemReason || '待补充',
    detail: resolveExpenseDescriptionDetail(itemType, itemLocation),
    amount: amountDisplay,
    status: isSystemGenerated ? '系统计算' : attachments.length ? '已识别' : '待补充',
    tone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'bad',
    attachmentStatus: isSystemGenerated ? '无需附件' : attachments.length ? '已关联票据' : '未上传',
    attachmentHint: isSystemGenerated ? '根据出差天数与职级自动测算' : attachments.length ? attachmentName || attachments[0] : resolveExpenseUploadHint(),
    attachmentTone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'missing',
    attachments,
    riskLabel: String(source?.riskLabel || '').trim() || '无',
    riskText,
    riskTone: String(source?.riskTone || '').trim() || 'low'
  }
}

export function rebuildExpenseItems(items, requestModel) {
  const sortedItems = [...items]
    .filter((item) => !isIgnorableExpenseDraftPlaceholder(item))
    .sort((left, right) => Number(isSystemGeneratedExpenseItemSource(left)) - Number(isSystemGeneratedExpenseItemSource(right)))
  const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, requestModel)
  return sortedItems.map((item, index) => buildExpenseItemViewModel(item, index, requestModel, travelTimeLabelMap))
}

export function buildExpenseDraftIssues(item) {
  const issues = []
  if (item.isSystemGenerated || isSystemGeneratedExpenseItemSource(item)) {
    return issues
  }
  if (isIgnorableExpenseDraftPlaceholder(item)) {
    return issues
  }
  const locationRequired = isLocationRequiredExpenseType(item.itemType)
  const hasUploadedReceipt = hasUploadedReceiptReference(item)

  if (!hasUploadedReceipt && !isValidIsoDate(item.itemDate)) {
    issues.push('缺少日期')
  }
  if (isPlaceholderValue(item.itemType)) {
    issues.push('缺少费用项目')
  }
  if (!hasUploadedReceipt && isPlaceholderValue(item.itemReason)) {
    issues.push('缺少说明')
  } else if (!hasUploadedReceipt && isRouteDescriptionExpenseType(item.itemType) && !isValidRouteDescription(item.itemReason)) {
    issues.push('行程说明格式错误')
  }
  if (!hasUploadedReceipt && locationRequired && isPlaceholderValue(item.itemLocation)) {
    issues.push('缺少地点')
  }
  if (!hasUploadedReceipt && (!Number.isFinite(Number(item.itemAmount)) || Number(item.itemAmount) <= 0)) {
    issues.push('缺少金额')
  }
  if (isAttachmentRequiredExpenseItem(item) && !hasUploadedReceipt) {
    issues.push('缺少票据标识')
  }

  return issues
}

export function buildDraftBlockingIssues(request, expenseItems) {
  const issues = []
  const isApplication = isApplicationDocumentRequest(request)
  const locationRequired = isLocationRequiredExpenseType(request.typeCode)
  const normalizedItems = Array.isArray(expenseItems) ? expenseItems : []
  const effectiveItems = normalizedItems.filter((item) => !isIgnorableExpenseDraftPlaceholder(item))
  const itemAmountTotal = effectiveItems.reduce((sum, item) => {
    const amount = Number(item?.itemAmount || 0)
    return Number.isFinite(amount) && amount > 0 ? sum + amount : sum
  }, 0)
  const hasValidItemDate = effectiveItems.some((item) => isValidIsoDate(item?.itemDate))
  const hasValidItemType = effectiveItems.some((item) => !isPlaceholderValue(item?.itemType))
  const hasValidItemReason = effectiveItems.some((item) => !isPlaceholderValue(item?.itemReason))
  const hasValidItemLocation = effectiveItems.some((item) => !isPlaceholderValue(item?.itemLocation))

  if (isPlaceholderValue(request.profileName)) {
    issues.push('申请人未完善')
  }
  if (isApplication) {
    if (isPlaceholderValue(request.typeLabel)) {
      issues.push('申请类型未完善')
    }
    if (isPlaceholderValue(request.reason)) {
      issues.push('申请事由未完善')
    }
    if (isPlaceholderValue(request.location)) {
      issues.push('业务地点未完善')
    }
    if (isPlaceholderValue(request.occurredDisplay)) {
      issues.push('申请时间未完善')
    }
    if (!Number.isFinite(Number(request.amountValue)) || Number(request.amountValue) <= 0) {
      issues.push('预计总费用未完善')
    }
    return [...new Set(issues)]
  }

  if (isPlaceholderValue(request.typeLabel) && !hasValidItemType) {
    issues.push('报销类型未完善')
  }
  if (isPlaceholderValue(request.reason) && !hasValidItemReason) {
    issues.push('报销事由未完善')
  }
  if (locationRequired && isPlaceholderValue(request.location) && !hasValidItemLocation) {
    issues.push('业务地点未完善')
  }
  if (isPlaceholderValue(request.occurredDisplay) && !hasValidItemDate) {
    issues.push('发生时间未完善')
  }
  if ((!Number.isFinite(Number(request.amountValue)) || Number(request.amountValue) <= 0) && itemAmountTotal <= 0) {
    issues.push('报销金额未完善')
  }
  if (!effectiveItems.length) {
    issues.push('费用明细不能为空')
  }

  normalizedItems.forEach((item, index) => {
    buildExpenseDraftIssues(item).forEach((issue) => {
      issues.push(`费用明细第 ${index + 1} 条${issue}`)
    })
  })

  return [...new Set(issues)]
}

export function mapIssueToAdvice(issue) {
  const text = String(issue || '').trim()
  if (!text) {
    return ''
  }

  if (text === '费用明细不能为空') {
    return '先新增至少 1 条费用明细，再补充金额、用途和附件。'
  }
  if (text === '申请人未完善') {
    return '补充申请人信息，确保审批单据归属明确。'
  }
  if (text === '所属部门未完善') {
    return '补充所属部门，便于财务和审批人识别成本归属。'
  }
  if (text === '报销类型未完善') {
    return '选择报销类型，明确本次费用归类。'
  }
  if (text === '申请类型未完善') {
    return '补充申请类型，明确本次申请的费用或业务场景。'
  }
  if (text === '报销事由未完善') {
    return '补充报销事由，说明本次费用用途。'
  }
  if (text === '申请事由未完善') {
    return '补充申请事由，说明本次申请的业务背景。'
  }
  if (text === '业务地点未完善') {
    return '补充业务地点，方便审核业务发生场景。'
  }
  if (text === '发生时间未完善') {
    return '补充费用发生时间，确保单据时间完整。'
  }
  if (text === '申请时间未完善') {
    return '补充申请时间或行程时间，确保申请周期完整。'
  }
  if (text === '报销金额未完善') {
    return '补充报销金额，并与费用明细金额保持一致。'
  }
  if (text === '预计总费用未完善') {
    return '补充预计总费用，供审批人判断预算占用和申请额度。'
  }

  const itemMatch = text.match(/^费用明细第\s*(\d+)\s*条(.+)$/)
  if (!itemMatch) {
    return text
  }

  const [, indexText, fieldText] = itemMatch
  const labelPrefix = `完善第 ${indexText} 条费用明细`
  if (fieldText === '缺少日期') {
    return `${labelPrefix}的发生日期。`
  }
  if (fieldText === '缺少费用项目') {
    return `${labelPrefix}的费用项目。`
  }
  if (fieldText === '缺少说明') {
    return `${labelPrefix}的用途说明。`
  }
  if (fieldText === '行程说明格式错误') {
    return `${labelPrefix}的行程说明，格式应为“起始地-目的地”。`
  }
  if (fieldText === '缺少地点') {
    return `${labelPrefix}的业务地点。`
  }
  if (fieldText === '缺少金额') {
    return `${labelPrefix}的金额。`
  }
  if (fieldText === '缺少票据标识') {
    return `为第 ${indexText} 条费用明细上传或关联票据附件。`
  }

  return `${labelPrefix}。`
}
