import { buildApplicationFieldsFromOntology } from './expenseApplicationOntology.js'
import { evaluateLocalApplicationIntentGate } from './expenseApplicationIntentGate.js'
import {
  formatApplicationEstimateMoney,
  parseApplicationEstimateMoney,
  buildSystemApplicationEstimate
} from './expenseApplicationEstimate.js'
import {
  APPLICATION_POLICY_PENDING_TEXT,
  APPLICATION_PREVIEW_FIELD_DEFINITIONS,
  APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT,
  buildMissingFields,
  buildTransportEstimateFromPolicyResult,
  buildTransportPolicyText,
  ensureApplicationPolicyFields,
  formatDailyPolicyMoney,
  formatPolicyMoney,
  isApplicationPreviewValueProvided,
  isTravelApplicationType,
  normalizeAmountFromOntology,
  normalizeApplicationLocationBoundary,
  normalizeApplicationTypeLabel,
  normalizeTypedOntologyAmount,
  parseApplicationDaysValue,
  parseMoneyNumber,
  resolveApplicationAmount,
  resolveApplicationDays,
  resolveApplicationFieldLabel,
  resolveApplicationLocation,
  resolveApplicationReason,
  resolveApplicationSourceValidationIssues,
  resolveApplicationTimeWithDefault,
  resolveApplicationTransportMode,
  resolveApplicationTripDateParts,
  resolveApplicationType,
  resolveApplicationValidationIssues,
  resolveCurrentUserDepartment,
  resolveCurrentUserGrade,
  resolveCurrentUserManagerName,
  resolveCurrentUserPosition,
  resolveDaysFromDateRange,
  resolveModelRefinedTransportMode,
  resolveProvidedValue
} from './expenseApplicationPreviewParsing.js'
export {
  APPLICATION_PREVIEW_FIELD_DEFINITIONS,
  APPLICATION_TRANSPORT_MODE_OPTIONS,
  applicationDateRangesOverlap,
  normalizeTransportModeOption,
  resolveApplicationDateRange,
  resolveApplicationDaysFromDateRange,
  resolveApplicationTimeLabel,
  shouldRequireApplicationModelReview
} from './expenseApplicationPreviewParsing.js'

export function buildApplicationPolicyEstimateRequest(preview = {}, currentUser = {}) {
  const normalized = normalizeApplicationPreview(preview)
  const fields = normalized.fields || {}
  const days = parseApplicationDaysValue(fields.days) || parseApplicationDaysValue(resolveDaysFromDateRange(fields.time))
  const location = String(fields.location || '').trim()
  const grade = String(fields.grade || resolveCurrentUserGrade(currentUser)).trim()
  const applicationType = String(fields.applicationType || '').trim()
  const transportMode = String(fields.transportMode || '').trim()
  const shouldEstimate = /差旅|住宿|交通/.test(applicationType) || Boolean(transportMode)
  const blockingLocationIssue = (normalized.validationIssues || []).find((issue) => issue?.field === 'location')

  if (blockingLocationIssue) {
    return {
      canCalculate: false,
      reason: blockingLocationIssue.message || '地点需修正',
      payload: null
    }
  }

  if (!shouldEstimate || !days || !location) {
    return {
      canCalculate: false,
      reason: '缺少地点或天数',
      payload: null
    }
  }

  return {
    canCalculate: true,
    reason: '',
    payload: {
      days,
      location,
      grade,
      transport_mode: transportMode || null,
      origin_location: String(
        currentUser.location
        || currentUser.officeLocation
        || currentUser.office_location
        || currentUser.baseCity
        || currentUser.base_city
        || ''
      ).trim() || null,
      travel_date: resolveApplicationTripDateParts(fields).startDate || null
    }
  }
}

export function applyApplicationPolicyEstimateResult(preview = {}, result = {}, currentUser = {}) {
  const fields = {
    ...(preview?.fields || {})
  }
  const hotelRate = formatPolicyMoney(result?.hotel_rate)
  const hotelAmount = formatPolicyMoney(result?.hotel_amount)
  const allowanceRate = formatPolicyMoney(result?.total_allowance_rate)
  const allowanceAmount = formatPolicyMoney(result?.allowance_amount)
  const matchedCity = String(result?.matched_city || fields.location || '').trim()
  const grade = String(result?.grade || fields.grade || resolveCurrentUserGrade(currentUser)).trim()
  if (isTravelApplicationType(fields.applicationType) && !String(fields.transportMode || '').trim()) {
    const days = Number(result?.days) || parseApplicationDaysValue(fields.days) || 1
    const baseTotalAmount = parseMoneyNumber(result?.hotel_amount) + parseMoneyNumber(result?.allowance_amount)
    const baseTotalDisplay = Number.isFinite(baseTotalAmount) && baseTotalAmount > 0
      ? formatPolicyMoney(baseTotalAmount)
      : ''
    return normalizeApplicationPreview({
      ...preview,
      fields: {
        ...fields,
        grade,
        days: parseApplicationDaysValue(fields.days) ? fields.days : `${days}天`,
        lodgingDailyCap: formatDailyPolicyMoney(result?.hotel_rate),
        subsidyDailyCap: formatDailyPolicyMoney(result?.total_allowance_rate),
        transportPolicy: APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT,
        policyEstimate: baseTotalDisplay
          ? `交通待补充 + 住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${baseTotalDisplay}元（${days}天，不含交通）`
          : APPLICATION_POLICY_PENDING_TEXT,
        amount: baseTotalDisplay ? `${baseTotalDisplay}元（不含交通）` : fields.amount,
        matchedCity,
        ruleName: String(result?.rule_name || '').trim(),
        ruleVersion: String(result?.rule_version || '').trim(),
        hotelAmount: hotelAmount ? `${hotelAmount}元` : '',
        allowanceAmount: allowanceAmount ? `${allowanceAmount}元` : '',
        transportEstimatedAmount: '',
        transportEstimateDate: '',
        transportQueryLatencyMs: '',
        transportEstimateSource: '',
        transportEstimateConfidence: '',
        policyTotalAmount: baseTotalDisplay ? `${baseTotalDisplay}元（不含交通）` : ''
      },
      policyEstimateStatus: 'pending'
    })
  }
  const days = Number(result?.days) || parseApplicationDaysValue(fields.days) || 1
  let systemEstimate = buildSystemApplicationEstimate({
    transportMode: fields.transportMode,
    location: matchedCity || fields.location,
    time: fields.time,
    lodgingAmount: result?.hotel_amount,
    allowanceAmount: result?.allowance_amount
  })
  const policyTransportEstimate = buildTransportEstimateFromPolicyResult(result, fields)
  if (policyTransportEstimate) {
    const lodging = parseApplicationEstimateMoney(result?.hotel_amount)
    const allowance = parseApplicationEstimateMoney(result?.allowance_amount)
    const backendTotal = parseApplicationEstimateMoney(result?.total_amount)
    const totalAmount = backendTotal > 0
      ? backendTotal
      : policyTransportEstimate.amount + lodging + allowance
    systemEstimate = {
      transportEstimate: policyTransportEstimate,
      transportAmount: policyTransportEstimate.amount,
      lodgingAmount: lodging,
      allowanceAmount: allowance,
      totalAmount,
      transportAmountDisplay: policyTransportEstimate.amountDisplay,
      lodgingAmountDisplay: formatApplicationEstimateMoney(lodging),
      allowanceAmountDisplay: formatApplicationEstimateMoney(allowance),
      totalAmountDisplay: formatApplicationEstimateMoney(totalAmount)
    }
  }
  const transportEstimate = systemEstimate.transportEstimate
  const transportText = transportEstimate
    ? `交通 ${systemEstimate.transportAmountDisplay}元 + `
    : ''
  const totalAmount = systemEstimate.totalAmountDisplay
  const amount = totalAmount ? `${totalAmount}元` : fields.amount

  return normalizeApplicationPreview({
    ...preview,
    fields: {
      ...fields,
      grade,
      days: parseApplicationDaysValue(fields.days) ? fields.days : `${days}天`,
      lodgingDailyCap: formatDailyPolicyMoney(result?.hotel_rate),
      subsidyDailyCap: formatDailyPolicyMoney(result?.total_allowance_rate),
      transportPolicy: buildTransportPolicyText(fields.transportMode, matchedCity || fields.location, transportEstimate, fields.time),
      policyEstimate: `${transportText}住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${totalAmount}元（${days}天）`,
      amount,
      matchedCity,
      ruleName: String(result?.rule_name || '').trim(),
      ruleVersion: String(result?.rule_version || '').trim(),
      hotelAmount: hotelAmount ? `${hotelAmount}元` : '',
      allowanceAmount: allowanceAmount ? `${allowanceAmount}元` : '',
      transportEstimatedAmount: systemEstimate.transportAmountDisplay ? `${systemEstimate.transportAmountDisplay}元` : '',
      transportEstimateDate: transportEstimate?.queryDate || '',
      transportQueryLatencyMs: transportEstimate?.simulatedLatencyMs ? `${transportEstimate.simulatedLatencyMs}ms` : '',
      transportEstimateSource: transportEstimate?.source || '',
      transportEstimateConfidence: transportEstimate?.confidence || '',
      policyTotalAmount: totalAmount ? `${totalAmount}元` : ''
    },
    policyEstimate: {
      ...result,
      grade,
      matchedCity,
      transport_estimate: transportEstimate,
      system_total_amount: systemEstimate.totalAmount
    },
    policyEstimateStatus: 'completed'
  })
}

export function refreshApplicationPreviewTransportEstimate(preview = {}) {
  const normalized = normalizeApplicationPreview(preview)
  const fields = { ...(normalized.fields || {}) }
  const policyResult = normalized.policyEstimate && typeof normalized.policyEstimate === 'object'
    ? normalized.policyEstimate
    : {}
  const location = String(fields.matchedCity || policyResult.matched_city || fields.location || '').trim()
  const hotelAmountSource = fields.hotelAmount || policyResult.hotel_amount || 0
  const allowanceAmountSource = fields.allowanceAmount || policyResult.allowance_amount || 0
  const systemEstimate = buildSystemApplicationEstimate({
    transportMode: fields.transportMode,
    location,
    time: fields.time,
    lodgingAmount: hotelAmountSource,
    allowanceAmount: allowanceAmountSource
  })
  const transportEstimate = systemEstimate.transportEstimate
  if (!transportEstimate) return normalized

  const hotelAmount = formatPolicyMoney(hotelAmountSource)
  const allowanceAmount = formatPolicyMoney(allowanceAmountSource)
  const hasPolicyAmounts = parseMoneyNumber(hotelAmountSource) > 0 || parseMoneyNumber(allowanceAmountSource) > 0
  const nextFields = {
    ...fields,
    transportPolicy: buildTransportPolicyText(fields.transportMode, location, transportEstimate, fields.time),
    transportEstimatedAmount: systemEstimate.transportAmountDisplay ? `${systemEstimate.transportAmountDisplay}元` : '',
    transportEstimateDate: transportEstimate.queryDate || '',
    transportQueryLatencyMs: transportEstimate.simulatedLatencyMs ? `${transportEstimate.simulatedLatencyMs}ms` : '',
    transportEstimateSource: transportEstimate.source || '',
    transportEstimateConfidence: transportEstimate.confidence || ''
  }

  if (hasPolicyAmounts) {
    const days = Number(policyResult.days) || parseApplicationDaysValue(fields.days) || 1
    const totalAmount = systemEstimate.totalAmountDisplay
    nextFields.policyEstimate = `交通 ${systemEstimate.transportAmountDisplay}元 + 住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${totalAmount}元（${days}天）`
    nextFields.amount = totalAmount ? `${totalAmount}元` : nextFields.amount
    nextFields.policyTotalAmount = totalAmount ? `${totalAmount}元` : ''
  }

  return normalizeApplicationPreview({
    ...normalized,
    fields: nextFields,
    policyEstimate: {
      ...policyResult,
      matchedCity: location,
      transport_estimate: transportEstimate,
      system_total_amount: systemEstimate.totalAmount
    }
  })
}

export function applyApplicationPolicyEstimateError(preview = {}, error = null, currentUser = {}) {
  const fields = { ...(preview?.fields || {}) }
  const message = String(error?.message || error || '').trim()
  return normalizeApplicationPreview({
    ...preview,
    fields: {
      ...fields,
      grade: fields.grade || resolveCurrentUserGrade(currentUser),
      transportPolicy: buildTransportPolicyText(fields.transportMode, fields.location, null, fields.time),
      policyEstimate: message ? `规则中心暂未完成测算：${message}` : APPLICATION_POLICY_PENDING_TEXT
    },
    policyEstimateStatus: message ? 'failed' : 'pending'
  })
}

export function shouldUseLocalApplicationPreview(rawText, options = {}) {
  return evaluateLocalApplicationIntentGate(rawText, options).allowed
}

export function normalizeApplicationPreview(preview = {}) {
  const fields = ensureApplicationPolicyFields(preview?.fields || {})
  const missingFields = buildMissingFields(fields)
  const validationIssues = [
    ...resolveApplicationValidationIssues(fields),
    ...resolveApplicationSourceValidationIssues(preview?.sourceText, fields, preview)
  ]
  const editableFields = Array.isArray(preview?.editableFields)
    ? preview.editableFields
    : Array.isArray(preview?.editable_fields)
      ? preview.editable_fields
      : null
  return {
    ...preview,
    ...(editableFields
      ? {
          editableFields: editableFields
            .map((field) => String(field || '').trim())
            .filter(Boolean)
        }
      : {}),
    fields,
    missingFields,
    validationIssues,
    readyToSubmit: missingFields.length === 0 && validationIssues.length === 0
  }
}

function resolveApplicationPreviewEditableFields(preview = {}) {
  const source = Array.isArray(preview?.editableFields)
    ? preview.editableFields
    : Array.isArray(preview?.editable_fields)
      ? preview.editable_fields
      : null
  if (!Array.isArray(source)) {
    return null
  }
  const fields = new Set(
    source
      .map((field) => String(field || '').trim())
      .filter(Boolean)
  )
  if (fields.has('time')) {
    fields.add('time_return')
  }
  return fields
}

function isApplicationPreviewFieldEditable(preview = {}, item = {}, rowKey = '') {
  if (item.editable === false) {
    return false
  }
  const editableFields = resolveApplicationPreviewEditableFields(preview)
  if (!editableFields) {
    return true
  }
  return editableFields.has(rowKey)
}

export function applyApplicationBusinessTimeContext(preview = {}, businessTimeContext = null) {
  if (!businessTimeContext || typeof businessTimeContext !== 'object') {
    return normalizeApplicationPreview(preview)
  }

  const startDate = String(businessTimeContext.start_date || '').trim()
  const endDate = String(businessTimeContext.end_date || startDate).trim()
  const displayValue = String(
    businessTimeContext.business_time ||
    businessTimeContext.time_range ||
    businessTimeContext.display_value ||
    ''
  ).trim()
  const time = startDate && endDate
    ? (startDate === endDate ? startDate : `${startDate} 至 ${endDate}`)
    : displayValue
  if (!time) {
    return normalizeApplicationPreview(preview)
  }

  const normalized = normalizeApplicationPreview(preview)
  const fields = normalized.fields || {}
  return normalizeApplicationPreview({
    ...normalized,
    fields: {
      ...fields,
      time,
      days: resolveDaysFromDateRange(time) || fields.days
    }
  })
}

export function buildModelRefinedApplicationPreview(localPreview = {}, ontology = {}, rawText = '', currentUser = {}) {
  const currentFields = localPreview?.fields || {}
  const ontologyFields = buildApplicationFieldsFromOntology(ontology || {}, rawText, currentUser)
  const parseStrategy = String(ontology?.parse_strategy || '').trim()
  const refinedFields = {
    ...currentFields,
    applicationType: normalizeApplicationTypeLabel(
      ontologyFields.expenseTypeLabel,
      currentFields.applicationType
    ),
    time: resolveProvidedValue(ontologyFields.timeRange, currentFields.time),
    location: normalizeApplicationLocationBoundary(
      resolveProvidedValue(ontologyFields.location, currentFields.location)
    ),
    reason: resolveProvidedValue(ontologyFields.reason, currentFields.reason),
    days: resolveProvidedValue(ontologyFields.days, currentFields.days),
    transportMode: resolveModelRefinedTransportMode(ontologyFields, rawText, currentFields),
    amount: normalizeAmountFromOntology(ontologyFields, currentFields.amount),
    transportEstimatedAmount: normalizeTypedOntologyAmount(
      ontologyFields.transportEstimatedAmount || ontologyFields.trainEstimatedAmount || ontologyFields.flightEstimatedAmount,
      currentFields.transportEstimatedAmount
    ),
    trainEstimatedAmount: normalizeTypedOntologyAmount(ontologyFields.trainEstimatedAmount, currentFields.trainEstimatedAmount),
    flightEstimatedAmount: normalizeTypedOntologyAmount(ontologyFields.flightEstimatedAmount, currentFields.flightEstimatedAmount),
    hotelAmount: normalizeTypedOntologyAmount(ontologyFields.hotelAmount, currentFields.hotelAmount),
    allowanceAmount: normalizeTypedOntologyAmount(ontologyFields.allowanceAmount, currentFields.allowanceAmount),
    policyTotalAmount: normalizeTypedOntologyAmount(ontologyFields.policyTotalAmount, currentFields.policyTotalAmount),
    reimbursementAmount: normalizeTypedOntologyAmount(ontologyFields.reimbursementAmount, currentFields.reimbursementAmount),
    grade: resolveProvidedValue(currentFields.grade, resolveCurrentUserGrade(currentUser)),
    applicant: resolveProvidedValue(ontologyFields.applicant, currentFields.applicant),
    department: resolveProvidedValue(ontologyFields.department, currentFields.department || resolveCurrentUserDepartment(currentUser)),
    position: resolveProvidedValue(currentFields.position, resolveCurrentUserPosition(currentUser)),
    managerName: resolveProvidedValue(
      ontologyFields.managerName,
      currentFields.managerName || resolveCurrentUserManagerName(currentUser)
    )
  }

  return normalizeApplicationPreview({
    ...localPreview,
    sourceText: String(rawText || localPreview.sourceText || '').trim(),
    fields: refinedFields,
    modelRefined: true,
    parseStrategy,
    modelReviewStatus: parseStrategy === 'llm_primary' ? 'completed' : 'fallback'
  })
}

export function buildApplicationPreviewRows(preview = {}) {
  const normalized = normalizeApplicationPreview(preview)
  const fields = normalized.fields || {}
  return APPLICATION_PREVIEW_FIELD_DEFINITIONS.flatMap((item) => {
    if (item.key === 'time' && isTravelApplicationType(fields.applicationType)) {
      const tripDates = resolveApplicationTripDateParts(fields)
      const rawValue = fields[item.key]
      const missing = item.required !== false && !isApplicationPreviewValueProvided(rawValue)
      return [
        {
          ...item,
          label: '出发时间',
          value: tripDates.startDate || '待补充',
          editable: isApplicationPreviewFieldEditable(normalized, item, 'time'),
          highlight: Boolean(item.highlight),
          missing
        },
        {
          key: 'time_return',
          label: '返回时间',
          value: tripDates.endDate || '待补充',
          editable: isApplicationPreviewFieldEditable(normalized, item, 'time_return'),
          highlight: Boolean(item.highlight),
          missing
        }
      ]
    }

    const rawValue = fields[item.key]
    const value = String(rawValue || '').trim() || '待补充'
    return [{
      ...item,
      label: resolveApplicationFieldLabel(item, fields),
      value,
      editable: isApplicationPreviewFieldEditable(normalized, item, item.key),
      highlight: Boolean(item.highlight),
      missing: item.required !== false && !isApplicationPreviewValueProvided(rawValue)
    }]
  })
}

export function buildApplicationPreviewSubmitText(preview = {}) {
  const rows = buildApplicationPreviewRows(preview)
  return [
    '费用申请确认提交',
    ...rows.map((row) => `${row.label}：${row.value}`),
    '',
    '确认提交'
  ].join('\n')
}

export function buildLocalApplicationPreview(rawText, currentUser = {}, options = {}) {
  const sourceText = String(rawText || '').trim()
  const explicitDays = resolveApplicationDays(sourceText)
  const time = resolveApplicationTimeWithDefault(sourceText, explicitDays, options)
  const days = explicitDays || resolveDaysFromDateRange(time)
  const location = resolveApplicationLocation(sourceText)
  const fields = {
    applicationType: resolveApplicationType(sourceText),
    time,
    location,
    reason: resolveApplicationReason(sourceText, { location }),
    days,
    transportMode: resolveApplicationTransportMode(sourceText),
    amount: resolveApplicationAmount(sourceText),
    grade: resolveCurrentUserGrade(currentUser),
    applicant: currentUser.name || currentUser.username || '当前用户',
    department: resolveCurrentUserDepartment(currentUser) || '待补充',
    position: resolveCurrentUserPosition(currentUser) || '待补充',
    managerName: resolveCurrentUserManagerName(currentUser) || '待补充'
  }

  return normalizeApplicationPreview({
    sourceText,
    fields,
    modelReviewStatus: 'local'
  })
}

export function buildApplicationTemplatePreview(currentUser = {}) {
  return normalizeApplicationPreview({
    sourceText: '快速发起申请',
    fields: {
      applicationType: '费用申请',
      time: '',
      location: '',
      reason: '',
      days: '',
      transportMode: '',
      amount: '',
      grade: resolveCurrentUserGrade(currentUser),
      applicant: currentUser.name || currentUser.username || '当前用户',
      department: resolveCurrentUserDepartment(currentUser) || '待补充',
      position: resolveCurrentUserPosition(currentUser) || '待补充',
      managerName: resolveCurrentUserManagerName(currentUser) || '待补充'
    },
    modelReviewStatus: 'template'
  })
}

export function buildLocalApplicationPreviewMessage(preview) {
  const normalized = normalizeApplicationPreview(preview)
  const modelReviewStatus = String(normalized.modelReviewStatus || '').trim()
  const editMode = Boolean(normalized.applicationEditMode || normalized.application_edit_mode)
  if (editMode) {
    return '我已载入原申请信息。请只修改事由、时间、地点和出行方式；职级、负责人、标准和费用会按规则带入或重新测算。'
  }
  return [
    modelReviewStatus === 'completed'
      ? '我已完成模型复核，并整理成下方表格。请核查识别结果；点击对应行即可直接编辑。'
      : modelReviewStatus === 'fallback'
        ? '模型复核没有返回稳定结果，我已先按规则兜底整理成下方表格。请重点核查识别结果；点击对应行即可直接编辑。'
        : modelReviewStatus === 'failed'
          ? '模型复核暂时失败，我先保留一份临时核对表，方便您核查和补充信息。点击对应行即可直接编辑。'
          : modelReviewStatus === 'template'
            ? '我已为您准备好费用申请模板。本步骤不调用大模型，也不会保存草稿；请点击对应行直接填写。'
            : '我先整理出下方表格，请核查识别结果。点击对应行即可直接编辑。'
  ].join('\n')
}

export function buildApplicationPreviewFooterMessage(preview) {
  const normalized = normalizeApplicationPreview(preview)
  const missingFields = Array.isArray(normalized.missingFields) ? normalized.missingFields : []
  const validationIssues = Array.isArray(normalized.validationIssues) ? normalized.validationIssues : []
  if (validationIssues.length) {
    return `${validationIssues[0].message} 请先修正后再提交申请。`
  }
  if (missingFields.length) {
    return `当前还需要补充：${missingFields.join('、')}。补齐后我再帮您提交申请。`
  }

  return '请确认上述的信息是否填写正确？如果准确无误，点击 [确认](#application-submit) 进入审批环节。'
}
