import { TRANSPORT_KEYWORD_PATTERN } from '../../utils/reimbursementTextInference.js'
import {
  EXPENSE_CODE_TO_PRESET_SCENE,
  EXPENSE_TYPE_LABELS,
  REVIEW_SCENE_OPTIONS,
  REVIEW_SCENE_OTHER_OPTION
} from './travelReimbursementReviewConstants.js'

export function cloneReviewEditFields(fields) {
  const items = Array.isArray(fields) ? fields : []
  return items.map((item) => ({
    key: String(item?.key || '').trim(),
    label: String(item?.label || '').trim(),
    value: String(item?.value || ''),
    placeholder: String(item?.placeholder || ''),
    required: Boolean(item?.required),
    field_type: String(item?.field_type || item?.fieldType || 'text').trim() || 'text',
    group: String(item?.group || 'basic').trim() || 'basic'
  }))
}

export function buildReviewFormValues(fields) {
  return cloneReviewEditFields(fields).reduce((result, item) => {
    if (!item.key) {
      return result
    }
    result[item.key] = String(item.value || '').trim()
    return result
  }, {})
}

const ONTOLOGY_REVIEW_FIELD_ALIASES = {
  expense_type: ['reimbursement_type', 'scene_label', 'expenseType'],
  time_range: ['business_time', 'businessTime', 'occurred_date', 'occurredDate'],
  location: ['business_location', 'businessLocation'],
  reason: ['reason_value', 'reasonValue', 'business_reason', 'businessReason'],
  transport_mode: ['transport_type', 'transportType', 'transportMode', 'application_transport_mode', 'applicationTransportMode'],
  attachments: ['attachment_names', 'attachmentNames'],
  customer_name: ['customerName'],
  merchant_name: ['merchantName']
}

const ONTOLOGY_REVIEW_CONTEXT_FIELDS = new Set([
  'expense_type',
  'time_range',
  'location',
  'reason',
  'amount',
  'transport_mode',
  'attachments',
  'customer_name',
  'merchant_name',
  'participants',
  'application_claim_id',
  'application_claim_no',
  'application_reason',
  'application_location',
  'application_amount',
  'application_amount_label',
  'application_business_time',
  'application_days',
  'application_transport_mode',
  'application_lodging_daily_cap',
  'application_subsidy_daily_cap',
  'application_transport_policy',
  'application_policy_estimate',
  'application_rule_name',
  'application_rule_version',
  'application_date'
])

export function normalizeReviewFormValuesToOntology(values = {}) {
  const source = values && typeof values === 'object' ? values : {}
  const normalized = {}
  Object.entries(source).forEach(([key, value]) => {
    const cleanedKey = String(key || '').trim()
    if (!cleanedKey) return
    normalized[cleanedKey] = String(value || '').trim()
  })

  Object.entries(ONTOLOGY_REVIEW_FIELD_ALIASES).forEach(([canonicalKey, aliases]) => {
    if (normalized[canonicalKey]) return
    const matchedAlias = aliases.find((alias) => normalized[alias])
    if (matchedAlias) {
      normalized[canonicalKey] = normalized[matchedAlias]
    }
  })

  return Object.fromEntries(
    Object.entries(normalized).filter(([key, value]) => ONTOLOGY_REVIEW_CONTEXT_FIELDS.has(key) && String(value || '').trim())
  )
}

export function buildBusinessTimeContextFromReviewValues(values = {}) {
  const timeText = String(values.time_range || values.business_time || values.occurred_date || '').trim()
  if (!timeText) {
    return null
  }

  const matchedDates = timeText.match(/\d{4}-\d{2}-\d{2}/g) || []
  if (!matchedDates.length) {
    return null
  }
  const startDate = matchedDates[0]
  const endDate = matchedDates[matchedDates.length - 1] || startDate
  if (!isValidIsoDateString(startDate) || !isValidIsoDateString(endDate) || startDate > endDate) {
    return null
  }
  const displayValue = startDate === endDate ? startDate : `${startDate} 至 ${endDate}`
  return {
    mode: startDate === endDate ? 'single' : 'range',
    start_date: startDate,
    end_date: endDate,
    display_value: displayValue
  }
}

export function buildReviewFormContextFromPayload(reviewPayload, inlineState = null) {
  if (!reviewPayload || typeof reviewPayload !== 'object') {
    return {}
  }

  const fallbackState = buildInlineReviewState(reviewPayload)
  const candidateState = inlineState || fallbackState
  const hasCandidateValue = Object.values(candidateState || {}).some((value) => {
    if (typeof value === 'number') return value > 0
    return Boolean(String(value || '').trim())
  })
  const state = hasCandidateValue ? candidateState : fallbackState
  const fields = mergeInlineReviewFields(reviewPayload.edit_fields || [], state)
  const values = buildReviewFormValues(fields)
  const slotMap = buildReviewSlotMap(reviewPayload)
  const inheritedTimeRange = String(
    slotMap.time_range?.normalized_value ||
      slotMap.time_range?.value ||
      values.time_range ||
      values.business_time ||
      values.occurred_date ||
      ''
  ).trim()
  if (inheritedTimeRange) {
    values.time_range = values.time_range || inheritedTimeRange
  }

  const ontologyValues = normalizeReviewFormValuesToOntology(values)
  const businessTimeContext = buildBusinessTimeContextFromReviewValues(ontologyValues)
  return {
    review_form_values: ontologyValues,
    ...(businessTimeContext ? { business_time_context: businessTimeContext } : {})
  }
}

export function buildReviewEditFieldMap(fields) {
  return cloneReviewEditFields(fields).reduce((result, item) => {
    if (!item.key) return result
    result[item.key] = item
    return result
  }, {})
}

export function createEmptyInlineReviewState() {
  return {
    occurred_date: '',
    amount: '',
    transport_type: '',
    scene_label: '',
    reason_value: '',
    customer_name: '',
    location: '',
    merchant_name: '',
    participants: '',
    attachment_names: '',
    attachment_count: 0,
    pending_attachment_count: 0,
    expense_type: ''
  }
}

export function isTravelReviewPayload(reviewPayload, inlineState = createEmptyInlineReviewState()) {
  const expenseType = resolveExpenseTypeCode(
    inlineState?.expense_type ||
      buildReviewSlotMap(reviewPayload).expense_type?.normalized_value ||
      buildReviewSlotMap(reviewPayload).expense_type?.value ||
      ''
  )
  if (['travel', 'hotel'].includes(expenseType)) {
    return true
  }

  return (Array.isArray(reviewPayload?.document_cards) ? reviewPayload.document_cards : []).some((item) => {
    const documentType = String(item?.document_type || '').trim().toLowerCase()
    const suggestedType = resolveExpenseTypeCode(item?.suggested_expense_type || item?.scene_label || '')
    return (
      ['flight_itinerary', 'train_ticket', 'hotel_invoice'].includes(documentType) ||
      ['travel', 'hotel'].includes(suggestedType)
    )
  })
}

export function resolveReviewTravelTransportType(reviewPayload, fallbackText = '') {
  const documents = Array.isArray(reviewPayload?.document_cards) ? reviewPayload.document_cards : []
  const labels = []

  const appendLabel = (label) => {
    if (label && !labels.includes(label)) {
      labels.push(label)
    }
  }

  for (const item of documents) {
    const documentType = String(item?.document_type || '').trim().toLowerCase()
    const text = [
      item?.filename,
      item?.summary,
      item?.scene_label,
      item?.suggested_expense_type,
      ...(Array.isArray(item?.fields) ? item.fields.map((field) => `${field?.label || ''}${field?.value || ''}`) : [])
    ].join(' ')
    const compact = text.replace(/\s+/g, '')

    if (documentType === 'flight_itinerary' || /飞机|机票|航班|登机牌/.test(compact)) {
      appendLabel('飞机')
    } else if (documentType === 'train_ticket' || /火车|高铁|动车|铁路|车票/.test(compact)) {
      appendLabel('火车/高铁')
    } else if (documentType === 'taxi_receipt' || /打车|网约车|出租车|滴滴|的士/.test(compact)) {
      appendLabel('打车/网约车')
    }
  }

  const fallback = String(fallbackText || '').replace(/\s+/g, '')
  if (!labels.length) {
    if (/飞机|机票|航班/.test(fallback)) appendLabel('飞机')
    if (/火车|高铁|动车|铁路/.test(fallback)) appendLabel('火车/高铁')
    if (/打车|网约车|出租车|滴滴|的士/.test(fallback)) appendLabel('打车/网约车')
  }

  return labels.join('、')
}

export function resolveReviewRecognizedSlotCards(reviewPayload) {
  return Array.isArray(reviewPayload?.slot_cards)
    ? reviewPayload.slot_cards.filter((item) => item.status !== 'missing')
    : []
}

export function resolveReviewMissingSlotCards(reviewPayload) {
  return Array.isArray(reviewPayload?.slot_cards)
    ? reviewPayload.slot_cards.filter((item) => item.status === 'missing')
    : []
}

export function resolveReviewExtraMissingLabels(reviewPayload) {
  const labels = Array.isArray(reviewPayload?.missing_slots)
    ? reviewPayload.missing_slots
      .map((item) => {
        if (item && typeof item === 'object') {
          return String(item.label || item.title || item.key || '').trim()
        }
        return String(item || '').trim()
      })
      .filter(Boolean)
    : []
  if (!labels.length) return []

  const slotLabels = new Set(
    (Array.isArray(reviewPayload?.slot_cards) ? reviewPayload.slot_cards : []).flatMap((item) => [
      String(item?.label || '').trim(),
      String(item?.key || '').trim()
    ]).filter(Boolean)
  )
  return labels.filter((label) => !slotLabels.has(label))
}

export function buildReviewRecognizedLines(reviewPayload) {
  return resolveReviewRecognizedSlotCards(reviewPayload)
    .filter((item) => String(item?.value || '').trim())
    .map((item) => `${item.label}：${item.value}`)
}

export function buildReviewSlotMap(reviewPayload) {
  return Object.fromEntries(
    (Array.isArray(reviewPayload?.slot_cards) ? reviewPayload.slot_cards : []).map((item) => [item.key, item])
  )
}

export function resolveExpenseTypeCode(value) {
  const normalized = String(value || '').trim()
  if (!normalized) return 'other'
  if (EXPENSE_TYPE_LABELS[normalized]) return normalized
  const matched = Object.entries(EXPENSE_TYPE_LABELS).find(([, label]) => label === normalized)
  return matched?.[0] || 'other'
}

export function isValidIsoDateString(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 parseAmountNumber(value) {
  const normalized = String(value || '')
    .replace(/[，,\s]/g, '')
    .replace(/[¥￥]/g, '')
    .replace(/元/g, '')
    .trim()

  if (!normalized || !/^\d+(?:\.\d+)?$/.test(normalized)) {
    return null
  }

  const amount = Number(normalized)
  return Number.isFinite(amount) ? amount : null
}

export function normalizeAmountValue(value) {
  const amount = parseAmountNumber(value)
  if (amount === null) {
    return ''
  }
  return Number.isInteger(amount) ? `${amount}元` : `${amount.toFixed(2).replace(/\.?0+$/, '')}元`
}

export function extractAmountInputValue(value) {
  const amount = parseAmountNumber(value)
  if (amount === null) {
    return String(value || '').trim()
  }
  return Number.isInteger(amount) ? String(amount) : amount.toFixed(2).replace(/\.?0+$/, '')
}

export function formatAmountDisplay(value) {
  const amount = parseAmountNumber(value)
  if (amount === null) {
    return String(value || '').trim()
  }

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

export function matchPresetSceneFromReason(reason) {
  const compactReason = String(reason || '').trim().replace(/\s+/g, '')
  if (!compactReason) {
    return ''
  }
  if (/请客户.*吃饭|客户.*吃饭|招待|宴请|接待|客户接待/.test(compactReason)) {
    return '请客户吃饭'
  }
  if (/出差行程|住宿报销|交通出行|会务活动/.test(compactReason)) {
    const matchedPreset = REVIEW_SCENE_OPTIONS.find((option) => compactReason.includes(option.replace(/\s+/g, '')))
    if (matchedPreset && matchedPreset !== REVIEW_SCENE_OTHER_OPTION) {
      return matchedPreset
    }
  }
  if (/出差|差旅/.test(compactReason)) {
    return '出差行程'
  }
  if (/酒店|住宿/.test(compactReason)) {
    return '住宿报销'
  }
  if (TRANSPORT_KEYWORD_PATTERN.test(compactReason)) {
    return '交通出行'
  }
  if (/会务|会议|参会|论坛|展会/.test(compactReason)) {
    return '会务活动'
  }
  return ''
}

export function mapOcrSceneLabelToPresetScene(sceneLabel, suggestedExpenseType = '') {
  const fromCode = EXPENSE_CODE_TO_PRESET_SCENE[resolveExpenseTypeCode(suggestedExpenseType)]
  if (fromCode) {
    return fromCode
  }

  const compactLabel = String(sceneLabel || '').trim().replace(/\s+/g, '')
  if (!compactLabel) {
    return ''
  }
  if (/差旅|出差/.test(compactLabel)) {
    return '出差行程'
  }
  if (/住宿|酒店/.test(compactLabel)) {
    return '住宿报销'
  }
  if (/交通/.test(compactLabel)) {
    return '交通出行'
  }
  if (/招待|餐饮|餐费|伙食/.test(compactLabel)) {
    return '请客户吃饭'
  }
  if (/会务|会议/.test(compactLabel)) {
    return '会务活动'
  }
  return ''
}

export function mapExpenseTypeLabelToPresetScene(expenseType) {
  const code = resolveExpenseTypeCode(expenseType)
  if (EXPENSE_CODE_TO_PRESET_SCENE[code]) {
    return EXPENSE_CODE_TO_PRESET_SCENE[code]
  }

  const compactLabel = String(expenseType || '').trim().replace(/\s+/g, '')
  if (!compactLabel) {
    return ''
  }
  if (compactLabel.includes('差旅') || compactLabel.includes('出差')) {
    return '出差行程'
  }
  if (compactLabel.includes('住宿') || compactLabel.includes('酒店')) {
    return '住宿报销'
  }
  if (compactLabel.includes('交通')) {
    return '交通出行'
  }
  if (compactLabel.includes('招待') || compactLabel.includes('餐饮') || compactLabel.includes('伙食')) {
    return '请客户吃饭'
  }
  if (compactLabel.includes('会务') || compactLabel.includes('会议')) {
    return '会务活动'
  }
  return matchPresetSceneFromReason(expenseType)
}

export function inferPresetSceneFromReview(reviewPayload, reasonValue = '', expenseType = '') {
  const documents = Array.isArray(reviewPayload?.document_cards) ? reviewPayload.document_cards : []
  if (documents.length) {
    const votes = new Map()
    for (const document of documents) {
      const preset =
        mapOcrSceneLabelToPresetScene(document.scene_label, document.suggested_expense_type)
        || mapExpenseTypeLabelToPresetScene(document.suggested_expense_type)
      if (!preset) {
        continue
      }
      votes.set(preset, (votes.get(preset) || 0) + 1)
    }
    if (votes.size) {
      return [...votes.entries()].sort((left, right) => right[1] - left[1])[0][0]
    }
  }

  const claimGroups = Array.isArray(reviewPayload?.claim_groups) ? reviewPayload.claim_groups : []
  if (claimGroups.length === 1) {
    const group = claimGroups[0]
    const preset =
      mapExpenseTypeLabelToPresetScene(group.expense_type)
      || mapOcrSceneLabelToPresetScene(group.scene_label, group.expense_type)
    if (preset) {
      return preset
    }
  }

  const fromReason = matchPresetSceneFromReason(reasonValue)
  if (fromReason) {
    return fromReason
  }

  const fromExpenseType = mapExpenseTypeLabelToPresetScene(expenseType)
  if (fromExpenseType) {
    return fromExpenseType
  }

  if (String(reasonValue || '').trim()) {
    return REVIEW_SCENE_OTHER_OPTION
  }
  return '待补充'
}

export function formatReviewSceneDisplayValue(inlineState) {
  const scene = String(inlineState?.scene_label || '').trim()
  if (!scene || scene === '待补充') {
    return '待补充'
  }
  if (scene === REVIEW_SCENE_OTHER_OPTION) {
    const detail = String(inlineState?.reason_value || '').trim()
    if (!detail) {
      return REVIEW_SCENE_OTHER_OPTION
    }
    return detail.length > 18 ? `${REVIEW_SCENE_OTHER_OPTION}：${detail.slice(0, 18)}...` : `${REVIEW_SCENE_OTHER_OPTION}：${detail}`
  }
  return scene
}

export function summarizeReviewScene(reason, expenseType = '', reviewPayload = null) {
  return inferPresetSceneFromReview(reviewPayload, reason, expenseType)
}

export function buildInlineReviewState(reviewPayload) {
  const slotMap = buildReviewSlotMap(reviewPayload)
  const editFieldMap = buildReviewEditFieldMap(reviewPayload?.edit_fields)
  const attachmentNames = String(
    editFieldMap.attachment_names?.value ||
      slotMap.attachments?.value ||
      (Array.isArray(reviewPayload?.document_cards) ? reviewPayload.document_cards.map((item) => item.filename).join('、') : '')
  ).trim()
  const attachmentCount = Array.isArray(reviewPayload?.document_cards)
    ? reviewPayload.document_cards.length
    : attachmentNames
      ? attachmentNames.split('、').filter(Boolean).length
      : 0
  const expenseType = String(editFieldMap.expense_type?.value || slotMap.expense_type?.value || '').trim()
  const reasonValue = String(
    editFieldMap.reason?.value || slotMap.reason?.raw_value || slotMap.reason?.value || ''
  ).trim()
  const sceneLabel = inferPresetSceneFromReview(reviewPayload, reasonValue, expenseType)
  const transportType = String(
    editFieldMap.transport_type?.value || resolveReviewTravelTransportType(reviewPayload, reasonValue)
  ).trim()

  return {
    occurred_date: String(
      editFieldMap.occurred_date?.value || slotMap.time_range?.normalized_value || slotMap.time_range?.value || ''
    ).trim(),
    amount: normalizeAmountValue(
      String(editFieldMap.amount?.value || slotMap.amount?.normalized_value || slotMap.amount?.value || '').trim()
    ),
    transport_type: transportType,
    scene_label: sceneLabel,
    reason_value:
      sceneLabel === REVIEW_SCENE_OTHER_OPTION
        ? reasonValue
        : String(slotMap.reason?.raw_value || '').trim() || reasonValue,
    customer_name: String(editFieldMap.customer_name?.value || slotMap.customer_name?.value || '').trim(),
    location: String(
      editFieldMap.business_location?.value ||
        editFieldMap.location?.value ||
        slotMap.location?.normalized_value ||
        slotMap.location?.value ||
        ''
    ).trim(),
    merchant_name: String(editFieldMap.merchant_name?.value || slotMap.merchant_name?.value || '').trim(),
    participants: String(editFieldMap.participants?.value || slotMap.participants?.value || '').trim(),
    attachment_names: attachmentNames,
    attachment_count: attachmentCount,
    pending_attachment_count: 0,
    expense_type: expenseType
  }
}


export function mergeInlineReviewFields(baseFields, inlineState) {
  const merged = cloneReviewEditFields(baseFields)
  const updateMap = {
    expense_type: inlineState.expense_type,
    transport_type: inlineState.transport_type,
    occurred_date: inlineState.occurred_date,
    amount: inlineState.amount,
    customer_name: inlineState.customer_name,
    business_location: inlineState.location,
    merchant_name: inlineState.merchant_name,
    participants: inlineState.participants,
    reason: inlineState.reason_value || inlineState.scene_label,
    attachment_names: inlineState.attachment_names
  }

  for (const item of merged) {
    if (!(item.key in updateMap)) continue
    item.value = String(updateMap[item.key] || '').trim()
  }

  return merged
}
