import {
  DOCUMENT_BACKED_EXPENSE_TYPES,
  HOTEL_DESCRIPTION_EXPENSE_TYPES,
  LONG_DISTANCE_TRAVEL_EXPENSE_TYPES,
  LOCATION_REQUIRED_EXPENSE_TYPES,
  ROUTE_DESCRIPTION_EXPENSE_TYPES,
  STANDARD_ADJUSTMENT_RISK_SOURCE,
  SYSTEM_GENERATED_EXPENSE_TYPES,
  formatAmount,
  formatDate,
  formatDateTime,
  normalizeText,
  parseNumber,
  parseOptionalAmount,
  resolveTypeLabel
} from './requestShared.js'
import {
  findRelatedApplicationEvent,
  resolveRelatedApplicationInfo
} from './requestRelatedApplication.js'

function buildStandardAdjustmentMapFromClaim(claim = {}) {
  const flags = Array.isArray(claim?.risk_flags_json)
    ? claim.risk_flags_json
    : Array.isArray(claim?.riskFlags)
      ? claim.riskFlags
      : []
  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()
    const reimbursableAmount = parseOptionalAmount(flag.reimbursable_amount ?? flag.reimbursableAmount)
    if (!itemId || reimbursableAmount === null) {
      return
    }
    adjustmentMap.set(itemId, {
      originalAmount: parseOptionalAmount(flag.original_amount ?? flag.originalAmount),
      reimbursableAmount,
      employeeAbsorbedAmount: parseOptionalAmount(flag.employee_absorbed_amount ?? flag.employeeAbsorbedAmount) || 0,
      message: String(flag.message || flag.summary || '').trim()
    })
  })

  return adjustmentMap
}

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

function isLocationRequiredExpenseType(typeCode) {
  return LOCATION_REQUIRED_EXPENSE_TYPES.has(normalizeExpenseType(typeCode))
}

function resolveLocationDisplay(location, typeCode) {
  const normalized = String(location || '').trim()
  if (normalized) {
    return normalized
  }

  return isLocationRequiredExpenseType(typeCode) ? '待补充' : '非必填'
}

function resolveExpenseDescriptionDetail(itemType, itemLocation) {
  const normalizedType = normalizeExpenseType(itemType)
  if (ROUTE_DESCRIPTION_EXPENSE_TYPES.has(normalizedType)) {
    return '起始地-目的地'
  }
  if (HOTEL_DESCRIPTION_EXPENSE_TYPES.has(normalizedType)) {
    return '目的地酒店'
  }
  return resolveLocationDisplay(itemLocation, normalizedType)
}

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

function buildTravelTimeLabelMap(items, claim) {
  const travelItems = items
    .map((item, index) => {
      const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type)
      return {
        id: resolveExpenseItemViewId(item, index, claim),
        index,
        itemType,
        itemDate: formatDate(item?.item_date),
        isSystemGenerated: Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(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()
  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
}

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

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

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

function hasRelatedApplicationContext(claim) {
  return Boolean(findRelatedApplicationEvent(claim))
}

function isDocumentBackedRawExpenseItem(item) {
  const invoiceId = normalizeText(item?.invoice_id || item?.invoiceId)
  if (invoiceId) {
    return true
  }

  return DOCUMENT_BACKED_EXPENSE_TYPES.has(normalizeExpenseType(item?.item_type || item?.itemType))
}

function extractTravelDayCount(value) {
  const matched = normalizeText(value).replace(/\s+/g, '').match(/(\d{1,2})天/)
  return matched ? parseNumber(matched[1]) : 0
}

function isStaleApplicationAllowanceRawItem(item, claim) {
  const itemType = normalizeExpenseType(item?.item_type || item?.itemType)
  if (itemType !== 'travel_allowance') {
    return false
  }

  const related = resolveRelatedApplicationInfo(claim)
  const applicationDays = extractTravelDayCount(related?.days)
  const itemDays = extractTravelDayCount(item?.item_reason || item?.itemReason)
  return applicationDays > 0 && itemDays > 0 && applicationDays !== itemDays
}

function isApplicationLinkPlaceholderRawItem(item, claim) {
  const itemType = normalizeExpenseType(item?.item_type || item?.itemType)
  if (SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType)) {
    return true
  }

  const claimType = normalizeExpenseType(claim?.expense_type || claim?.expenseType)
  if (itemType && claimType && itemType !== claimType) {
    return false
  }

  const reason = normalizeText(item?.item_reason || item?.itemReason)
  if (!reason || reason === '待补充') {
    return true
  }

  const related = resolveRelatedApplicationInfo(claim)
  const linkedReasons = new Set([
    normalizeText(claim?.reason),
    normalizeText(related?.reason)
  ].filter(Boolean))
  return linkedReasons.has(reason)
}

function filterVisibleExpenseRawItems(items, claim) {
  const rawItems = Array.isArray(items) ? items : []
  if (!rawItems.length || !hasRelatedApplicationContext(claim)) {
    return rawItems
  }

  const hasRealExpenseItem = rawItems.some((item) => (
    isDocumentBackedRawExpenseItem(item)
    && !SYSTEM_GENERATED_EXPENSE_TYPES.has(normalizeExpenseType(item?.item_type || item?.itemType))
  ))
  if (!hasRealExpenseItem) {
    return rawItems.filter((item) => !isApplicationLinkPlaceholderRawItem(item, claim))
  }

  return rawItems.filter((item) => {
    const itemType = normalizeExpenseType(item?.item_type || item?.itemType)
    if (SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType)) {
      return !isStaleApplicationAllowanceRawItem(item, claim)
    }
    return !isApplicationLinkPlaceholderRawItem(item, claim)
  })
}

function buildExpenseItems(claim, riskMeta) {
  if (!Array.isArray(claim?.items)) {
    return []
  }

  const normalizedRiskMeta = typeof riskMeta === 'string'
    ? { summary: riskMeta, tone: riskMeta === '无' ? 'low' : 'medium', label: riskMeta === '无' ? '无' : '待关注' }
    : {
        summary: String(riskMeta?.summary || '无').trim() || '无',
        tone: String(riskMeta?.tone || 'low').trim() || 'low',
        label: String(riskMeta?.label || '').trim() || (String(riskMeta?.summary || '').trim() === '无' ? '无' : '待关注')
      }

  const visibleItems = filterVisibleExpenseRawItems(claim.items, claim)
  const sortedItems = [...visibleItems].sort((left, right) => {
    const leftType = normalizeExpenseType(left?.item_type)
    const rightType = normalizeExpenseType(right?.item_type)
    return Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(leftType)) - Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(rightType))
  })
  const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, claim)
  const standardAdjustmentMap = buildStandardAdjustmentMapFromClaim(claim)

  return sortedItems.map((item, index) => {
    const invoiceId = String(item?.invoice_id || '').trim()
    const attachmentName = resolveAttachmentDisplayName(invoiceId)
    const attachments = invoiceId ? [attachmentName || invoiceId] : []
    const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type)
    const isSystemGenerated = Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType))
    const id = resolveExpenseItemViewId(item, index, claim)
    const itemTypeLabel = resolveTypeLabel(itemType)
    const itemLocation = String(item?.item_location || '').trim()
    const itemReason = String(item?.item_reason || '').trim()
    const itemNote = String(item?.item_note || item?.itemNote || '').trim()
    const itemAmount = parseNumber(item?.item_amount)
    const itemAmountDisplay = itemAmount > 0 ? formatAmount(itemAmount) : '待补充'
    const standardAdjustment = standardAdjustmentMap.get(id) || null
    const originalItemAmount = standardAdjustment?.originalAmount ?? itemAmount
    const reimbursableAmount = standardAdjustment?.reimbursableAmount ?? itemAmount
    const employeeAbsorbedAmount = standardAdjustment?.employeeAbsorbedAmount || Math.max(originalItemAmount - reimbursableAmount, 0)

    return {
      id,
      time: formatDate(item?.item_date) || '待补充',
      itemDate: formatDate(item?.item_date) || '',
      filledAt: formatDateTime(item?.created_at) || '待同步',
      itemType,
      itemReason,
      itemLocation,
      itemNote,
      itemAmount,
      originalItemAmount,
      originalAmountDisplay: originalItemAmount > 0 ? formatAmount(originalItemAmount) : itemAmountDisplay,
      reimbursableAmount,
      reimbursableAmountDisplay: reimbursableAmount > 0 ? formatAmount(reimbursableAmount) : '待补充',
      employeeAbsorbedAmount,
      employeeAbsorbedAmountDisplay: employeeAbsorbedAmount > 0 ? formatAmount(employeeAbsorbedAmount) : '',
      hasStandardAdjustment: reimbursableAmount >= 0 && reimbursableAmount < originalItemAmount,
      standardAdjustmentAccepted: Boolean(standardAdjustment),
      standardAdjustmentMessage: standardAdjustment?.message || '',
      invoiceId,
      isSystemGenerated,
      dayLabel: resolveExpenseTimeLabel({
        id,
        itemType,
        isSystemGenerated,
        claim,
        travelTimeLabelMap
      }),
      name: itemTypeLabel,
      category: itemTypeLabel,
      desc: itemReason || '待补充',
      detail: resolveExpenseDescriptionDetail(itemType, itemLocation),
      amount: itemAmountDisplay,
      status: isSystemGenerated ? '系统计算' : attachments.length ? '已识别' : '待补充',
      tone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'bad',
      attachmentStatus: isSystemGenerated ? '无需附件' : attachments.length ? '已关联票据' : '未上传',
      attachmentHint: isSystemGenerated ? '根据出差天数与职级自动测算' : attachments.length ? attachments[0] : '仅支持上传 1 张 JPG、PNG、PDF 单据',
      attachmentTone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'missing',
      attachments,
      riskLabel: normalizedRiskMeta.summary === '无' ? '无' : normalizedRiskMeta.label,
      riskText: normalizedRiskMeta.summary === '无' ? '' : normalizedRiskMeta.summary,
      riskTone: normalizedRiskMeta.summary === '无' ? 'low' : normalizedRiskMeta.tone
    }
  })
}

export {
  buildExpenseItems
}
