const REQUIRED_APPLICATION_EXPENSE_TYPES = new Set(['travel', 'meal'])

const APPLICATION_TYPE_ALIASES = {
  travel: new Set(['travel', 'travel_application']),
  meal: new Set([
    'meal',
    'entertainment',
    'meal_application',
    'entertainment_application',
    'business_entertainment_application',
    'hospitality_application'
  ])
}

const GENERIC_APPLICATION_TYPES = new Set(['application', 'expense_application'])
const BLOCKED_APPLICATION_STATUSES = new Set(['draft', 'returned', 'rejected', 'cancelled', 'canceled', 'deleted'])

const STATUS_LABELS = {
  submitted: '审批中',
  approved: '已审批',
  completed: '已完成',
  archived: '已归档',
  pending_payment: '待付款',
  paid: '已付款'
}

const EXPENSE_TYPE_LABELS = {
  travel: '差旅费',
  meal: '业务招待费'
}

function normalizeText(value) {
  return String(value || '').trim()
}

function normalizeLower(value) {
  return normalizeText(value).toLowerCase()
}

function uniqueValues(values) {
  return Array.from(new Set((Array.isArray(values) ? values : []).map(normalizeText).filter(Boolean)))
}

function normalizeClaimNo(claim) {
  return normalizeText(claim?.claim_no || claim?.claimNo).toUpperCase()
}

function normalizeExpenseType(claim) {
  return normalizeLower(claim?.expense_type || claim?.expenseType || claim?.type_code || claim?.typeCode)
}

function normalizeApplicationStatus(claim) {
  return normalizeLower(claim?.status || claim?.state || claim?.approval_status || claim?.approvalStatus)
}

function normalizeDocumentType(claim) {
  return normalizeLower(
    claim?.document_type_code
      || claim?.documentTypeCode
      || claim?.document_type
      || claim?.documentType
  )
}

function normalizeApplicationDate(claim) {
  return normalizeText(
    claim?.submitted_at
      || claim?.submittedAt
      || claim?.created_at
      || claim?.createdAt
      || claim?.occurred_at
      || claim?.occurredAt
  )
}

function toTimestamp(value) {
  const date = new Date(value)
  return Number.isNaN(date.getTime()) ? 0 : date.getTime()
}

function formatAmount(value) {
  const numberValue = Number(String(value ?? '').replace(/[^\d.-]/g, ''))
  if (!Number.isFinite(numberValue) || numberValue <= 0) {
    return ''
  }
  return `¥${new Intl.NumberFormat('zh-CN', {
    minimumFractionDigits: Number.isInteger(numberValue) ? 0 : 2,
    maximumFractionDigits: 2
  }).format(numberValue)}`
}

function includesAny(text, keywords) {
  const normalized = normalizeText(text)
  return keywords.some((keyword) => normalized.includes(keyword))
}

function buildApplicationKeywordText(claim) {
  return [
    claim?.reason,
    claim?.business_reason,
    claim?.title,
    claim?.summary,
    claim?.description,
    claim?.location,
    claim?.business_location,
    claim?.expense_type_label,
    claim?.expenseTypeLabel
  ].map(normalizeText).filter(Boolean).join(' ')
}

function matchesGenericApplicationByText(claim, expenseType) {
  const haystack = buildApplicationKeywordText(claim)
  if (expenseType === 'travel') {
    return includesAny(haystack, ['差旅', '出差', '住宿', '交通', '行程'])
  }
  if (expenseType === 'meal') {
    return includesAny(haystack, ['招待', '客户', '接待', '宴请', '用餐', '餐饮'])
  }
  return false
}

export function requiresApplicationBeforeReimbursement(expenseType) {
  return REQUIRED_APPLICATION_EXPENSE_TYPES.has(normalizeLower(expenseType))
}

export function getRequiredApplicationExpenseLabel(expenseType) {
  return EXPENSE_TYPE_LABELS[normalizeLower(expenseType)] || '报销'
}

export function isExpenseApplicationClaim(claim) {
  const documentType = normalizeDocumentType(claim)
  const expenseType = normalizeExpenseType(claim)
  const claimNo = normalizeClaimNo(claim)

  return documentType === 'application'
    || documentType === 'expense_application'
    || claimNo.startsWith('AP-')
    || claimNo.startsWith('APP-')
    || expenseType === 'application'
    || expenseType.endsWith('_application')
}

export function matchesRequiredApplicationExpenseType(claim, expenseType) {
  const normalizedExpenseType = normalizeLower(expenseType)
  const claimExpenseType = normalizeExpenseType(claim)
  const aliases = APPLICATION_TYPE_ALIASES[normalizedExpenseType] || new Set()

  if (aliases.has(claimExpenseType)) {
    return true
  }

  return GENERIC_APPLICATION_TYPES.has(claimExpenseType)
    && matchesGenericApplicationByText(claim, normalizedExpenseType)
}

export function isClaimOwnedByCurrentUser(claim, currentUser = {}) {
  const userIds = uniqueValues([
    currentUser.id,
    currentUser.employeeId,
    currentUser.employee_id,
    currentUser.employeeNo,
    currentUser.employee_no,
    currentUser.username,
    currentUser.email
  ])
  const claimIds = uniqueValues([
    claim?.employee_id,
    claim?.employeeId,
    claim?.employee_no,
    claim?.employeeNo,
    claim?.username,
    claim?.user_id,
    claim?.userId
  ])
  if (userIds.length && claimIds.length && claimIds.some((item) => userIds.includes(item))) {
    return true
  }

  const userNames = uniqueValues([
    currentUser.name,
    currentUser.user_name,
    currentUser.employeeName,
    currentUser.employee_name,
    currentUser.username
  ])
  const claimNames = uniqueValues([
    claim?.employee_name,
    claim?.employeeName,
    claim?.applicant,
    claim?.applicant_name,
    claim?.applicantName
  ])
  if (userNames.length && claimNames.length) {
    return claimNames.some((item) => userNames.includes(item))
  }

  return true
}

export function isUsableRequiredApplicationClaim(claim) {
  const status = normalizeApplicationStatus(claim)
  return !BLOCKED_APPLICATION_STATUSES.has(status)
}

export function normalizeRequiredApplicationCandidate(claim) {
  const claimNo = normalizeText(claim?.claim_no || claim?.claimNo)
  const location = normalizeText(claim?.location || claim?.business_location || claim?.businessLocation)
  const amountText = formatAmount(claim?.amount || claim?.budget_amount || claim?.budgetAmount)
  const status = normalizeApplicationStatus(claim)

  return {
    id: normalizeText(claim?.id || claim?.claim_id || claim?.claimId),
    claim_no: claimNo,
    expense_type: normalizeExpenseType(claim),
    reason: normalizeText(claim?.reason || claim?.business_reason || claim?.description || claim?.title),
    location,
    amount: normalizeText(claim?.amount || claim?.budget_amount || claim?.budgetAmount),
    amount_label: amountText,
    status,
    status_label: STATUS_LABELS[status] || normalizeText(claim?.approval_stage || claim?.approvalStage || status),
    application_date: normalizeApplicationDate(claim)
  }
}

export function filterRequiredApplicationCandidates(claimsPayload, expenseType, currentUser = {}) {
  const claims = Array.isArray(claimsPayload)
    ? claimsPayload
    : Array.isArray(claimsPayload?.items)
      ? claimsPayload.items
      : Array.isArray(claimsPayload?.claims)
        ? claimsPayload.claims
        : []

  return claims
    .filter((claim) => (
      isExpenseApplicationClaim(claim)
      && isUsableRequiredApplicationClaim(claim)
      && isClaimOwnedByCurrentUser(claim, currentUser)
      && matchesRequiredApplicationExpenseType(claim, expenseType)
    ))
    .map(normalizeRequiredApplicationCandidate)
    .sort((left, right) => toTimestamp(right.application_date) - toTimestamp(left.application_date))
}

export function buildRequiredApplicationActions(applications, actionType) {
  return (Array.isArray(applications) ? applications : []).map((application) => {
    const claimNo = normalizeText(application.claim_no) || '未编号申请单'
    const description = [
      application.status_label,
      application.location && `地点：${application.location}`,
      application.amount_label && `预算：${application.amount_label}`,
      application.reason && `事由：${application.reason}`
    ].filter(Boolean).join(' · ')

    return {
      label: claimNo,
      description,
      icon: 'mdi mdi-file-link-outline',
      action_type: actionType,
      payload: {
        application_claim_id: application.id,
        application_claim_no: application.claim_no,
        application_expense_type: application.expense_type,
        application_reason: application.reason,
        application_location: application.location,
        application_amount: application.amount,
        application_amount_label: application.amount_label,
        application_status: application.status,
        application_status_label: application.status_label,
        application_date: application.application_date
      }
    }
  })
}

export function buildRequiredApplicationSelectionText(expenseType, applications) {
  const label = getRequiredApplicationExpenseLabel(expenseType)
  return [
    `发起“${label}”报销前，需要先关联对应的申请单。`,
    '',
    `我查到 ${applications.length} 个可关联申请单，请先选择其中一个。`,
    '选择后，我再继续向你收集本次报销依据。'
  ].join('\n')
}

export function buildRequiredApplicationMissingText(expenseType) {
  const label = getRequiredApplicationExpenseLabel(expenseType)
  return [
    `发起“${label}”报销前，需要先关联对应的申请单。`,
    '',
    `我没有查到你名下可关联的“${label}”申请单，所以当前不能继续这类报销流程。`,
    '请先切换到申请助手发起相关申请；申请单存在后，再回到报销助手继续。'
  ].join('\n')
}
