import { buildMockApplicationTransportEstimate } from './expenseApplicationEstimate.js'
import { getTodayDateValue } from './workbenchComposerDate.js'

export {
  resolveCurrentUserDepartment,
  resolveCurrentUserGrade,
  resolveCurrentUserManagerName,
  resolveCurrentUserPosition
} from './expenseApplicationUserProfile.js'

export const APPLICATION_PREVIEW_FIELD_DEFINITIONS = [
  { key: 'applicationType', label: '申请类型' },
  { key: 'applicant', label: '姓名', editable: false, required: false },
  { key: 'grade', label: '职级', highlight: true, editable: false, required: false },
  { key: 'department', label: '部门', editable: false, required: false },
  { key: 'position', label: '岗位', editable: false, required: false },
  { key: 'managerName', label: '直属领导', editable: false, required: false },
  { key: 'time', label: '申请时间' },
  { key: 'location', label: '地点' },
  { key: 'reason', label: '事由' },
  { key: 'days', label: '天数' },
  { key: 'transportMode', label: '出行方式' },
  { key: 'lodgingDailyCap', label: '住宿上限/天', highlight: true, editable: false, required: false },
  { key: 'subsidyDailyCap', label: '补贴标准/天', highlight: true, editable: false, required: false },
  { key: 'transportPolicy', label: '交通费用口径', highlight: true, editable: false, required: false },
  { key: 'policyEstimate', label: '规则测算参考', highlight: true, editable: false, required: false },
  { key: 'amount', label: '系统预估费用', highlight: true, editable: false, required: false }
]

export const APPLICATION_TRANSPORT_MODE_OPTIONS = ['火车', '飞机', '轮船']

export const APPLICATION_POLICY_PENDING_TEXT = '填写地点和天数后自动测算'
export const APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT = '选择火车、飞机或轮船后自动预估交通费用'
const APPLICATION_LOCATION_BUSINESS_ACTION_PATTERN = /(?:支撑|支持|辅助|部署|上线|实施|验收|项目)/u
const APPLICATION_LOCATION_BUSINESS_OBJECT_PATTERN = /(?:服务器|系统|仿生产|生产环境|测试环境)/u
const APPLICATION_LOCATION_ADDRESS_HINT_PATTERN = /(?:省|市|区|县|自治州|州|镇|乡|街道|路|街|大道|园区|大厦|中心|基地|机场|车站|高铁站|火车站|酒店|楼|号)$/u
const APPLICATION_LOCATION_PREFIX_CANDIDATES = [
  '北京',
  '北京市',
  '上海',
  '上海市',
  '天津',
  '天津市',
  '重庆',
  '重庆市',
  '广州',
  '深圳',
  '杭州',
  '南京',
  '苏州',
  '成都',
  '武汉',
  '西安',
  '郑州',
  '长沙',
  '青岛',
  '厦门',
  '宁波',
  '合肥',
  '济南',
  '福州',
  '九江',
  '伊犁'
].sort((left, right) => right.length - left.length)

export function resolveApplicationTimeLabel(applicationType = '') {
  const label = String(applicationType || '').trim()
  if (/差旅|出差/.test(label)) return '出发时间'
  if (/招待|宴请|餐饮/.test(label)) return '招待时间'
  return '申请时间'
}

export function resolveApplicationFieldLabel(item, fields = {}) {
  if (item.key === 'time') {
    return resolveApplicationTimeLabel(fields.applicationType)
  }
  return item.label
}

export function isTravelApplicationType(applicationType = '') {
  return /差旅|出差/.test(String(applicationType || '').trim())
}

export function resolveApplicationTripDateParts(fields = {}) {
  const timeText = String(fields.time || '').trim()
  const matchedDates = timeText.match(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/g) || []
  const startDate = normalizeDateText(matchedDates[0] || timeText)
  const explicitEndDate = normalizeDateText(matchedDates[matchedDates.length - 1] || '')
  const inferredEndDate = explicitEndDate && explicitEndDate !== startDate
    ? explicitEndDate
    : buildEndDateFromDays(startDate, fields.days)

  return {
    startDate,
    endDate: inferredEndDate || explicitEndDate || startDate
  }
}

function compactText(value) {
  return String(value || '').replace(/\s+/g, '')
}

function looksLikeStructuredTravelApplication(text) {
  const source = String(text || '')
  return /(?:发生时间|业务发生时间|申请时间|时间)\s*[:：]/.test(source)
    && /(?:地点|业务地点|发生地点|目的地)\s*[:：]/.test(source)
    && /(?:天数|出差天数|申请天数)\s*[:：]?\s*(?:\d+|[一二两三四五六七八九十]{1,3})\s*天/.test(source)
}

function resolveFirstMatch(text, patterns = []) {
  for (const pattern of patterns) {
    const match = text.match(pattern)
    const value = String(match?.groups?.value || match?.[1] || '').trim()
    if (value) return value.replace(/[，。；;]$/, '')
  }
  return ''
}

function normalizeDateText(value) {
  return String(value || '').replace(/[/.]/g, '-').replace(/\s+/g, '')
}

function parseIsoDate(value) {
  const match = normalizeDateText(value).match(/^(20\d{2})-(\d{1,2})-(\d{1,2})$/)
  if (!match) return null
  const [, year, month, day] = match
  const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)))
  return Number.isNaN(date.getTime()) ? null : date
}

function formatIsoDate(date) {
  return date.toISOString().slice(0, 10)
}

function buildEndDateFromDays(startText, daysText = '') {
  const days = parseApplicationDaysValue(daysText)
  const start = parseIsoDate(startText)
  if (!days || !start) return ''
  const end = new Date(start.getTime())
  end.setUTCDate(end.getUTCDate() + Math.max(days - 1, 0))
  return formatIsoDate(end)
}

function buildDateFromMonthDay(year, month, day) {
  const normalized = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`
  return parseIsoDate(normalized) ? normalized : ''
}

function resolveShortMonthDayRange(text, options = {}) {
  const match = String(text || '').match(
    /(?<startMonth>\d{1,2})月(?<startDay>\d{1,2})日?\s*(?:至|到|~|—|–|--|-)\s*(?:(?<endMonth>\d{1,2})月)?(?<endDay>\d{1,2})日/u
  )
  if (!match?.groups) return ''

  const referenceYear = Number(resolvePreviewToday(options).slice(0, 4))
  const startMonth = Number(match.groups.startMonth)
  const startDay = Number(match.groups.startDay)
  const endMonth = Number(match.groups.endMonth || match.groups.startMonth)
  const endDay = Number(match.groups.endDay)
  const startDate = buildDateFromMonthDay(referenceYear, startMonth, startDay)
  const endYear = endMonth < startMonth ? referenceYear + 1 : referenceYear
  const endDate = buildDateFromMonthDay(endYear, endMonth, endDay)
  if (!startDate || !endDate) return ''
  return startDate === endDate ? startDate : `${startDate} 至 ${endDate}`
}

export function resolveDaysFromDateRange(rangeText) {
  const match = String(rangeText || '').match(/(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})\s*至\s*(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/)
  if (!match) return ''
  const start = parseIsoDate(match[1])
  const end = parseIsoDate(match[2])
  if (!start || !end) return ''
  const diffDays = Math.round((end.getTime() - start.getTime()) / 86400000)
  return diffDays >= 0 ? `${diffDays + 1}天` : ''
}

export function resolveApplicationDaysFromDateRange(rangeText) {
  return resolveDaysFromDateRange(rangeText)
}

export function resolveApplicationValidationIssues(fields = {}) {
  const issues = []
  const locationIssue = resolveApplicationLocationValidationIssue(fields.location)
  if (locationIssue) {
    issues.push(locationIssue)
  }

  const rangeDaysText = resolveDaysFromDateRange(fields.time)
  const rangeDays = parseApplicationDaysValue(rangeDaysText)
  const explicitDays = parseApplicationDaysValue(fields.days)
  if (rangeDays && explicitDays && rangeDays !== explicitDays) {
    issues.push({
      code: 'time_days_conflict',
      field: 'days',
      message: `申请时间 ${fields.time} 按自然日为 ${rangeDays} 天，但填写的是 ${explicitDays} 天。`
    })
  }
  return issues
}

export function resolveApplicationLocationValidationIssue(location = '') {
  const text = normalizeApplicationLocationForValidation(location)
  if (!text || ['待补充', '待确认', '未知', '暂无', '无'].includes(text)) {
    return null
  }
  if (!applicationLocationMixesBusinessContent(text)) {
    return null
  }
  return {
    code: 'invalid_application_location',
    field: 'location',
    message: `地点“${text}”不是可直接用于差旅测算的真实地点，请填写城市或具体地址，例如“上海”；业务事项请放在事由中。`
  }
}

function normalizeApplicationLocationForValidation(value) {
  return normalizeApplicationLocationBoundary(value)
    .replace(/^(?:地点|业务地点|发生地点|目的地)[:：]/u, '')
    .replace(/^(?:去|到|赴|前往)/u, '')
    .replace(/[：:，,。；;、]+$/u, '')
}

export function normalizeApplicationLocationBoundary(value) {
  const text = compactText(value)
    .replace(/^(?:地点|业务地点|发生地点|目的地)[:：]/u, '')
    .replace(/^(?:去|到|赴|前往)/u, '')
    .replace(/[：:，,。；;、]+$/u, '')
  if (!text || /[，,、]/u.test(text)) {
    return text
  }
  if (
    !APPLICATION_LOCATION_BUSINESS_ACTION_PATTERN.test(text) &&
    !APPLICATION_LOCATION_BUSINESS_OBJECT_PATTERN.test(text)
  ) {
    return text
  }

  const matchedPrefix = APPLICATION_LOCATION_PREFIX_CANDIDATES.find((candidate) => text.startsWith(candidate))
  if (!matchedPrefix) {
    return text
  }
  return matchedPrefix.replace(/^(北京|上海|天津|重庆)市$/u, '$1')
}

function applicationLocationMixesBusinessContent(text) {
  if (/[，,、]/u.test(text)) {
    return false
  }
  if (APPLICATION_LOCATION_BUSINESS_ACTION_PATTERN.test(text)) {
    return true
  }
  return APPLICATION_LOCATION_BUSINESS_OBJECT_PATTERN.test(text) &&
    !APPLICATION_LOCATION_ADDRESS_HINT_PATTERN.test(text)
}

function shouldTrustModelApplicationFields(preview = {}) {
  const status = String(preview?.modelReviewStatus || '').trim()
  const strategy = String(preview?.parseStrategy || preview?.parse_strategy || '').trim()
  return Boolean(preview?.modelRefined)
    || status === 'completed'
    || strategy === 'llm_primary'
}

export function resolveApplicationSourceValidationIssues(sourceText = '', fields = {}, preview = {}) {
  if (shouldTrustModelApplicationFields(preview)) {
    return []
  }

  const issues = []
  const locationCandidates = extractApplicationLocationCandidates(sourceText)
  if (locationCandidates.length > 1) {
    issues.push({
      code: 'location_candidates_conflict',
      field: 'location',
      message: `当前输入里同时出现多个地点：${locationCandidates.join('、')}。请确认本次申请地点。`
    })
  }

  const transportCandidates = extractApplicationTransportCandidates(sourceText)
  if (transportCandidates.length > 1) {
    issues.push({
      code: 'transport_candidates_conflict',
      field: 'transportMode',
      message: `当前输入里同时出现多个出行方式：${transportCandidates.join('、')}。请确认本次申请使用哪一种。`
    })
  }

  const amountCandidates = extractApplicationAmountCandidates(sourceText)
  if (amountCandidates.length > 1) {
    issues.push({
      code: 'amount_candidates_conflict',
      field: 'amount',
      message: `当前输入里同时出现多个金额：${amountCandidates.join('、')}。请确认本次申请金额。`
    })
  }
  return issues
}

export function shouldRequireApplicationModelReview(rawText = '') {
  const text = String(rawText || '').trim()
  const compact = compactText(text)
  if (!compact) return false

  const hasDateRange = /(?:20\d{2}[-/.年]\d{1,2}[-/.月]\d{1,2}|(?:\d{1,2}月)?\d{1,2}日?)\s*(?:至|到|~|—|–|--|-)\s*(?:20\d{2}[-/.年]\d{1,2}[-/.月]\d{1,2}|\d{1,2}月?\d{1,2}日?)/u.test(text)
  const hasTravelIntent = /差旅|出差|去|到|赴|前往/.test(compact)
  const hasTransport = /高铁|动车|火车|铁路|飞机|机票|航班|轮船|船票|客轮|渡轮/.test(compact)
  const hasBusinessPurpose = /服务|支撑|支持|辅助|部署|实施|验收|拜访|对接|沟通|培训|会议|采购|安装|维护|上线|调试|项目/.test(compact)
  const hasInlinePurpose = hasBusinessPurpose && !/(?:事由|申请事由|出差事由|原因|用途)\s*[:：]/.test(text)
  const hasMultipleClauses = /[，,。；;\n]/.test(text) || compact.length >= 24
  const signalCount = [hasDateRange, hasTravelIntent, hasTransport, hasBusinessPurpose].filter(Boolean).length

  return (hasInlinePurpose && signalCount >= 2) || (hasMultipleClauses && signalCount >= 3)
}

export function resolveApplicationDateRange(rangeText, daysText = '') {
  const matchedDates = String(rangeText || '').match(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/g) || []
  const startDate = normalizeDateText(matchedDates[0] || '')
  const explicitEndDate = normalizeDateText(matchedDates[matchedDates.length - 1] || '')
  const inferredEndDate = explicitEndDate && explicitEndDate !== startDate
    ? explicitEndDate
    : buildEndDateFromDays(startDate, daysText)
  const endDate = inferredEndDate || explicitEndDate || startDate
  const start = parseIsoDate(startDate)
  const end = parseIsoDate(endDate)
  if (!start || !end) {
    return null
  }
  const orderedStart = start.getTime() <= end.getTime() ? start : end
  const orderedEnd = start.getTime() <= end.getTime() ? end : start
  return {
    startDate: formatIsoDate(orderedStart),
    endDate: formatIsoDate(orderedEnd),
    startTime: orderedStart.getTime(),
    endTime: orderedEnd.getTime()
  }
}

export function applicationDateRangesOverlap(leftRange, rightRange) {
  if (!leftRange || !rightRange) {
    return false
  }
  return leftRange.startTime <= rightRange.endTime && rightRange.startTime <= leftRange.endTime
}

function resolvePreviewToday(options = {}) {
  const explicitToday = String(options.today || options.currentDate || '').trim()
  if (parseIsoDate(explicitToday)) return normalizeDateText(explicitToday)
  if (options.now instanceof Date && !Number.isNaN(options.now.getTime())) {
    return getTodayDateValue(options.now)
  }
  return getTodayDateValue()
}

export function resolveApplicationType(text) {
  const compact = compactText(text)
  if (looksLikeStructuredTravelApplication(text)) return '差旅费用申请'
  if (/差旅|出差|高铁|动车|火车|飞机|机票|航班|酒店|住宿/.test(compact)) return '差旅费用申请'
  if (/交通|出租车|的士|网约车|打车|通勤/.test(compact)) return '交通费用申请'
  if (/住宿|酒店/.test(compact)) return '住宿费用申请'
  if (/会务|会议|发布会|展会/.test(compact)) return '会务费用申请'
  if (/采购|办公用品|文具|设备|耗材/.test(compact)) return '采购费用申请'
  if (/培训|课程|学习/.test(compact)) return '培训费用申请'
  return '费用申请'
}

export function resolveApplicationAmount(text) {
  const compact = compactText(text)
  const labeled = resolveFirstMatch(text, [
    /(?:用户预估费用|预估费用|申请金额|预计金额|预计费用|预计总费用|预算|金额|费用)\s*[:：]?\s*(?<value>\d+(?:\.\d+)?\s*(?:万|千|k|K)?)/u,
    /(?<value>\d+(?:\.\d+)?\s*(?:(?:万|千|k|K)\s*(?:元|块|人民币)?|(?:元|块|人民币)))/u
  ])
  const normalized = normalizeApplicationAmountText(labeled)
  if (normalized) return normalized
  if (/不知道预算|预算不清楚|预算待定|待测算/.test(compact)) return '待测算'
  return ''
}

function normalizeApplicationAmountText(value) {
  const text = String(value || '').replace(/[,，]/g, '').trim()
  const match = text.match(/(?<number>\d+(?:\.\d+)?)\s*(?<unit>万|千|k|K)?/u)
  if (!match?.groups) return ''
  let amount = Number(match.groups.number)
  if (!Number.isFinite(amount) || amount <= 0) return ''
  const unit = String(match.groups.unit || '').toLowerCase()
  if (unit === '万') amount *= 10000
  if (unit === '千' || unit === 'k') amount *= 1000
  return `${Number.isInteger(amount) ? amount : Number(amount.toFixed(2))}元`
}

function extractApplicationLocationCandidates(text) {
  const candidates = []
  const labeled = resolveFirstMatch(text, [
    /(?:地点|业务地点|发生地点|目的地)\s*[:：]\s*(?<value>[^。；;\n，,]+)/u
  ])
  if (labeled) candidates.push(normalizeLocationCandidate(labeled))

  const compact = compactText(text)
  const patterns = [
    /(?:去|到|赴|前往)(?<value>[\u4e00-\u9fa5]{1,24})/gu,
    /(?<value>[\u4e00-\u9fa5]{1,12})(?:出差|驻场)/gu
  ]
  for (const pattern of patterns) {
    for (const match of compact.matchAll(pattern)) {
      candidates.push(normalizeLocationCandidate(match.groups?.value || ''))
    }
  }
  return uniqueApplicationCandidates(candidates)
    .filter((item) => !isInvalidApplicationLocationCandidate(item))
}

function normalizeLocationCandidate(value) {
  let cleaned = String(value || '').replace(/\s+/g, '')
  for (const marker of ['前往', '去', '到', '赴']) {
    if (cleaned.includes(marker)) {
      cleaned = cleaned.slice(cleaned.lastIndexOf(marker) + marker.length)
      break
    }
  }
  cleaned = cleaned
    .replace(/^(?:去|到|赴|前往)/u, '')
    .replace(/(?:出差|驻场|现场|支撑|支持|部署|上线|实施|拜访|验收|会议|采购|培训|协助|处理|办理|参加|进行).*$/u, '')
    .replace(/[：:，,。；;、\s]/g, '')
  return cleaned.replace(/^(北京|上海|天津|重庆)市$/u, '$1')
}

function isInvalidApplicationLocationCandidate(value) {
  const compact = compactText(value)
  if (!compact) return true
  if (/^(?:类型|申请类型|费用类型|报销类型)$/.test(compact)) return true
  if (/^(?:费用申请|差旅费用申请|交通费用申请|住宿费用申请|会务费用申请|采购费用申请|培训费用申请|报销申请|申请)$/.test(compact)) return true
  if (/(?:类型|申请类型|费用类型|报销类型)/.test(compact)) return true
  if (/(?:交通方式|出行方式|交通工具|预算|金额|费用|票据|附件|天数|时间|事由|原因|用途)/.test(compact)) return true
  return false
}

function extractApplicationTransportCandidates(text) {
  const compact = compactText(text)
  return uniqueApplicationCandidates([
    resolveApplicationTransportMode(resolveFirstMatch(text, [
      /(?:出行方式|交通方式|交通工具|出行工具)\s*[:：]\s*(?<value>[^。；;\n，,]+)/u
    ])),
    /高铁|动车|火车|铁路/.test(compact) ? '火车' : '',
    /飞机|机票|航班/.test(compact) ? '飞机' : '',
    /轮船|船票|客轮|渡轮|邮轮/.test(compact) ? '轮船' : ''
  ])
}

function extractApplicationAmountCandidates(text) {
  const candidates = []
  const source = String(text || '')
  const labelPattern = /(?:用户预估费用|预估费用|申请金额|预计金额|预计费用|预计总费用|预算|金额|费用)\s*[:：]?\s*(?<value>\d+(?:\.\d+)?\s*(?:万|千|k|K)?\s*(?:元|块|人民币)?)/gu
  for (const match of source.matchAll(labelPattern)) {
    candidates.push(normalizeApplicationAmountText(match.groups?.value || ''))
  }
  const amountPattern = /(?<value>\d+(?:\.\d+)?\s*(?:(?:万|千|k|K)\s*(?:元|块|人民币)?|(?:元|块|人民币)))/gu
  for (const match of source.matchAll(amountPattern)) {
    candidates.push(normalizeApplicationAmountText(match.groups?.value || ''))
  }
  return uniqueApplicationCandidates(candidates)
}

function uniqueApplicationCandidates(values) {
  return values
    .map((item) => String(item || '').trim())
    .filter(Boolean)
    .filter((item, index, list) => list.indexOf(item) === index)
}

export function parseApplicationDaysValue(value) {
  const match = String(value || '').match(/\d+/)
  const days = match ? Number(match[0]) : parseChineseNumber(value)
  return Number.isFinite(days) && days > 0 ? Math.max(1, Math.floor(days)) : 0
}

function parseChineseNumber(value) {
  const digits = {
    一: 1,
    二: 2,
    两: 2,
    三: 3,
    四: 4,
    五: 5,
    六: 6,
    七: 7,
    八: 8,
    九: 9
  }
  const text = String(value || '').match(/[一二两三四五六七八九十]{1,3}/)?.[0] || ''
  if (!text) return 0
  if (text === '十') return 10
  if (text.includes('十')) {
    const [left, right] = text.split('十')
    const tens = left ? digits[left] || 0 : 1
    const ones = right ? digits[right] || 0 : 0
    return tens * 10 + ones
  }
  return digits[text] || 0
}

export function parseMoneyNumber(value) {
  const normalized = String(value ?? '').replace(/[^\d.-]/g, '')
  const amount = Number(normalized)
  return Number.isFinite(amount) ? amount : null
}

export function formatPolicyMoney(value) {
  const amount = parseMoneyNumber(value)
  if (amount === null) return String(value || '').trim()
  return new Intl.NumberFormat('zh-CN', {
    minimumFractionDigits: 0,
    maximumFractionDigits: Number.isInteger(amount) ? 0 : 2
  }).format(amount)
}

export function formatDailyPolicyMoney(value) {
  const display = formatPolicyMoney(value)
  return display ? `${display}元/天` : APPLICATION_POLICY_PENDING_TEXT
}

export function buildTransportPolicyText(transportMode, location = '', transportEstimate = null, time = '') {
  const mode = String(transportMode || '').trim()
  const estimate = transportEstimate || buildMockApplicationTransportEstimate({ transportMode: mode, location, time })
  if (!estimate) return APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT
  return estimate.basisText
}

export function buildTransportEstimateFromPolicyResult(result = {}, fields = {}) {
  const amount = parseMoneyNumber(result?.transport_estimated_amount)
  if (!amount || amount <= 0) return null
  const amountDisplay = formatPolicyMoney(amount)
  const mode = String(result?.transport_mode || fields.transportMode || '').trim()
  const origin = String(result?.transport_origin || '').trim()
  const destination = String(result?.transport_destination || result?.matched_city || fields.location || '').trim()
  const basis = String(result?.transport_estimate_basis || '').trim()
  const ruleName = String(result?.transport_estimate_rule_name || '交通费用预估表').trim()
  const routeText = [origin, destination].filter(Boolean).join('-')
  const modeText = mode ? `${mode}往返` : '往返'
  const routeModeText = routeText ? `${routeText}${modeText}` : modeText
  const displayBasis = routeModeText && basis.startsWith(routeModeText)
    ? basis.slice(routeModeText.length).trim()
    : basis
  const basisSuffix = displayBasis ? `（${displayBasis}）` : ''
  return {
    mode,
    amount,
    amountDisplay,
    routeType: '往返',
    origin,
    destination,
    queryDate: String(result?.travel_date || '').trim(),
    source: String(result?.transport_estimate_source || 'basic_rule_transport_estimate').trim(),
    confidence: String(result?.transport_estimate_confidence || 'basic_rule').trim(),
    basis,
    ruleCode: String(result?.transport_estimate_rule_code || '').trim(),
    ruleName,
    ruleVersion: String(result?.transport_estimate_rule_version || '').trim(),
    basisText: `当前尚未接通实时票务价格查询 API，无法获取当前实际票价；先按《${ruleName}》${routeModeText}${basisSuffix}暂估 ${amountDisplay}元用于申请阶段预算占用，最终报销以实际票据金额为准`
  }
}

export function ensureApplicationPolicyFields(fields = {}) {
  const nextFields = { ...fields }
  if (!String(nextFields.lodgingDailyCap || '').trim()) {
    nextFields.lodgingDailyCap = APPLICATION_POLICY_PENDING_TEXT
  }
  if (!String(nextFields.subsidyDailyCap || '').trim()) {
    nextFields.subsidyDailyCap = APPLICATION_POLICY_PENDING_TEXT
  }
  if (!String(nextFields.transportPolicy || '').trim() || /实报实销/.test(String(nextFields.transportPolicy || ''))) {
    nextFields.transportPolicy = buildTransportPolicyText(nextFields.transportMode, nextFields.location, null, nextFields.time)
  }
  if (!String(nextFields.policyEstimate || '').trim()) {
    nextFields.policyEstimate = APPLICATION_POLICY_PENDING_TEXT
  }
  return nextFields
}

export function resolveApplicationDays(text) {
  const value = resolveFirstMatch(text, [
    /(?:出差|申请)?(?<value>\d+)\s*天/u,
    /(?<value>\d+)\s*(?:个)?工作日/u
  ])
  return value ? `${value}天` : ''
}

function resolveApplicationTime(text, daysText = '', options = {}) {
  const range = text.match(
    /(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})\s*(?:至|到|~|—|–|--)\s*(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u
  )
  if (range) {
    return `${normalizeDateText(range[1])} 至 ${normalizeDateText(range[2])}`
  }

  const shortMonthDayRange = resolveShortMonthDayRange(text, options)
  if (shortMonthDayRange) {
    return shortMonthDayRange
  }

  const single = resolveFirstMatch(text, [
    /(?:发生时间|业务发生时间|申请时间|时间)\s*[:：]\s*(?<value>20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u,
    /(?<value>20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u
  ])
  if (!single) return ''
  const normalized = normalizeDateText(single)
  const endDate = buildEndDateFromDays(normalized, daysText)
  return endDate && endDate !== normalized ? `${normalized} 至 ${endDate}` : normalized
}

export function resolveApplicationTimeWithDefault(text, daysText = '', options = {}) {
  const resolvedTime = resolveApplicationTime(text, daysText, options)
  if (resolvedTime || !parseApplicationDaysValue(daysText)) {
    return resolvedTime
  }

  const startDate = resolvePreviewToday(options)
  const endDate = buildEndDateFromDays(startDate, daysText)
  return endDate && endDate !== startDate ? `${startDate} 至 ${endDate}` : startDate
}

export function resolveApplicationLocation(text) {
  return normalizeApplicationLocationBoundary(resolveFirstMatch(text, [
    /(?:地点|业务地点|发生地点|目的地)\s*[:：]\s*(?<value>[^。；;\n]+)/u,
    /(?:去|到|前往)(?<value>[\u4e00-\u9fa5，,、]{2,24}?)(?:出差|支撑|支持|部署|开会|培训|拜访|验收|项目|客户|。|\s|$)/u
  ]))
}

function looksLikeTransportPromptText(text) {
  const compact = compactText(text)
  return /(?:还需要补充|当前还缺|缺少|请先补充|请选择|可以选择|可以选|打算怎么出行|怎么出行).{0,24}(?:出行方式|交通方式|交通工具)/u.test(compact)
    || /(?:出行方式|交通方式|交通工具).{0,24}(?:待补充|缺失|请选择|可以选择|可以选)/u.test(compact)
}

export function resolveApplicationTransportMode(text) {
  const labeled = resolveFirstMatch(text, [
    /(?:出行方式|交通方式|交通工具|出行工具)\s*[:：]\s*(?<value>[^。；;\n，,]+)/u
  ])
  const labeledMode = normalizeTransportModeOption(labeled, '')
  if (labeledMode && !looksLikeTransportPromptText(labeled) && !/(?:请选择|可以选择|可以选)/u.test(String(labeled || ''))) {
    return labeledMode
  }
  const fullTextLooksLikePrompt = looksLikeTransportPromptText(text)
  const segments = String(text || '')
    .split(/[\n，,。；;]+/u)
    .map((item) => item.trim())
    .filter(Boolean)
  for (const segment of segments) {
    if (looksLikeTransportPromptText(segment)) continue
    const compactSegment = compactText(segment)
    if (
      fullTextLooksLikePrompt
      && !/(?:申请|出差|去|到|赴|前往|服务|支撑|支持|部署|上线|实施|拜访|会议)/u.test(compactSegment)
    ) {
      continue
    }
    if (/高铁|动车|火车|铁路/.test(compactSegment)) return '火车'
    if (/飞机|机票|航班/.test(compactSegment)) return '飞机'
    if (/轮船|船票|客轮|渡轮/.test(compactSegment)) return '轮船'
  }
  if (fullTextLooksLikePrompt) return ''
  const compact = compactText(text)
  if (/高铁|动车|火车|铁路/.test(compact)) return '火车'
  if (/飞机|机票|航班/.test(compact)) return '飞机'
  if (/轮船|船票|客轮|渡轮/.test(compact)) return '轮船'
  return ''
}

function stripKnownContextFromReason(value, context = {}) {
  const location = String(context.location || '').trim()
  let cleaned = String(value || '')
    .replace(/(?:请直接生成申请单核对结果|信息足够时生成申请单|但在入库或提交审批前仍需让我确认|请直接生成报销核对结果|需要创建草稿、绑定附件或提交审批前仍需让我确认)[\s\S]*$/u, '')
    .replace(/(?:发生时间|业务发生时间|申请时间|时间)\s*[:：]\s*(?=[，,、。；;\s]|$)/gu, '')
    .replace(/(?:地点|业务地点|发生地点|目的地)\s*[:：]\s*(?=[，,、。；;\s]|$)/gu, '')
    .replace(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}\s*(?:至|到|~|—|–|--)\s*20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/gu, '')
    .replace(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/gu, '')
    .replace(/(?:\d{1,2}月)?\d{1,2}日?\s*(?:至|到|~|—|–|--|-)\s*(?:\d{1,2}月)?\d{1,2}日?/gu, '')
    .replace(/\d{1,2}月\d{1,2}日?/gu, '')
    .replace(/(?:出差|申请)?\d+\s*天/gu, '')
    .replace(/(?:用户预估费用|预估费用|预计总费用|预计费用|预计金额|申请金额|预算|金额|费用)\s*[:：]?\s*\d+(?:\.\d+)?\s*(?:元|块|人民币)?/gu, '')
    .replace(/(?:高铁|动车|火车|铁路|飞机|机票|航班|轮船|船票|客轮|渡轮|出租车|的士|网约车|打车|自驾)/gu, '')
    .replace(/[，,、。；;]+/g, '，')
    .replace(/^\s*(去|到|前往)/u, '')
    .replace(/^[，\s]+|[，\s]+$/g, '')
    .trim()

  if (location) {
    const escapedLocation = location.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    cleaned = cleaned
      .replace(new RegExp(`^${escapedLocation}(?:出差)?(?:，|,|、)?`, 'u'), '')
      .replace(new RegExp(`^(?:去|到|前往)${escapedLocation}(?:出差)?(?:，|,|、)?`, 'u'), '')
      .trim()
  }

  return cleaned
}

function pickBusinessReasonSegment(text) {
  const segments = String(text || '')
    .split(/[，,、。；;\n]+/u)
    .map((item) => item.trim())
    .filter((item) => item && !isSystemGeneratedReasonText(item))
  return segments.find((item) => /服务|支撑|支持|部署|实施|验收|拜访|对接|沟通|培训|会议|采购|安装|维护|上线|调试|项目/.test(item)) || ''
}

function isSystemGeneratedReasonText(value = '') {
  const compact = compactText(value)
  return compact.startsWith('小财管家继续执行')
    || /请直接生成申请单核对结果|信息足够时生成申请单|入库或提交审批前|请直接生成报销核对结果/.test(compact)
    || compact.startsWith('处理要求')
    || compact.startsWith('已识别信息')
    || compact.startsWith('用户已补充')
    || /^(?:类型|申请类型|费用类型|报销类型)[:：]?(?:差旅费用申请|交通费用申请|住宿费用申请|费用申请|差旅费|交通费|住宿费)?$/.test(compact)
}

export function resolveApplicationReason(text, context = {}) {
  const labeled = resolveFirstMatch(text, [
    /(?:事由|申请事由|出差事由|原因|用途)\s*[:：]\s*(?<value>[^，。；;\n]+)/u
  ])
  if (labeled) return stripKnownContextFromReason(labeled, context)
  const cleaned = String(text || '')
    .replace(/^\s*(我想|我要|帮我)?\s*(先)?\s*(发起|提交|申请)?\s*(一笔)?\s*(费用申请|申请)\s*/u, '')
  const withoutContext = stripKnownContextFromReason(cleaned, context)
  const businessSegment = pickBusinessReasonSegment(withoutContext)
  if (businessSegment) return stripKnownContextFromReason(businessSegment, context)
  if (isSystemGeneratedReasonText(withoutContext)) return ''
  return withoutContext
}

export function isApplicationPreviewValueProvided(value) {
  const normalized = String(value || '').trim()
  return Boolean(normalized) && !['待测算', '待补充', '未知'].includes(normalized)
}

export function resolveProvidedValue(value, fallback = '') {
  return isApplicationPreviewValueProvided(value) ? String(value).trim() : fallback
}

export function normalizeApplicationTypeLabel(value, fallback = '') {
  const label = String(value || '').trim()
  if (!label || label === '其他费用') return fallback || '费用申请'
  if (label.endsWith('费用申请') || label.endsWith('申请')) return label
  if (label.endsWith('费用')) return `${label}申请`
  if (label.endsWith('费')) return `${label.slice(0, -1)}费用申请`
  return `${label}申请`
}

export function normalizeTransportModeOption(value, fallback = '') {
  const text = String(value || '').trim()
  if (/飞机|机票|航班/.test(text)) return '飞机'
  if (/轮船|船票|客轮|渡轮|邮轮/.test(text)) return '轮船'
  if (/火车|高铁|动车|铁路|列车/.test(text)) return '火车'
  return APPLICATION_TRANSPORT_MODE_OPTIONS.includes(text) ? text : fallback
}

export function resolveModelRefinedTransportMode(ontologyFields = {}, rawText = '', currentFields = {}) {
  const currentTransportMode = isApplicationPreviewValueProvided(currentFields.transportMode)
    ? String(currentFields.transportMode).trim()
    : ''
  const explicitTransportMode = resolveApplicationTransportMode(rawText)
  if (!explicitTransportMode) {
    return currentTransportMode
  }

  const ontologyTransportMode = normalizeTransportModeOption(ontologyFields.transportMode, '')
  if (ontologyTransportMode && ontologyTransportMode === explicitTransportMode) {
    return ontologyTransportMode
  }
  return currentTransportMode || explicitTransportMode
}

export function normalizeAmountFromOntology(fields = {}, fallback = '') {
  const numericAmount = Number(fields.amount || fields.policyTotalAmount || fields.reimbursementAmount || 0)
  if (Number.isFinite(numericAmount) && numericAmount > 0) {
    return `${numericAmount}元`
  }

  const display = String(fields.amountDisplay || '').trim()
  if (display && display !== '待补充') {
    const normalized = display.replace(/^¥\s*/, '').replace(/,/g, '').trim()
    return normalized.endsWith('元') ? normalized : `${normalized}元`
  }

  return fallback
}

export function normalizeTypedOntologyAmount(value, fallback = '') {
  const amount = Number(value || 0)
  if (Number.isFinite(amount) && amount > 0) {
    return `${amount}元`
  }
  return fallback
}

export function buildMissingFields(fields) {
  return APPLICATION_PREVIEW_FIELD_DEFINITIONS
    .filter((item) => item.key !== 'applicationType' && item.required !== false)
    .filter((item) => !isApplicationPreviewValueProvided(fields?.[item.key]))
    .map((item) => resolveApplicationFieldLabel(item, fields))
}
