import { ref } from 'vue'

import {
  AI_APPLICATION_ACTION_SAVE_DRAFT,
  AI_APPLICATION_ACTION_SUBMIT,
  createAiApplicationRequestId,
  forgetAiApplicationMemory,
  normalizeAiApplicationMemory,
  registerAiApplicationPreviewDecision,
  resolveAiApplicationLearningReceipts,
  resolveAiApplicationPreviewMemories,
  runAiApplicationPreviewAction
} from '../../services/aiApplicationPreviewActions.js'
import { normalizeApplicationPreview } from '../../utils/expenseApplicationPreview.js'

const DECISION_STATUS_REGISTERED = 'registered'
const DECISION_STATUS_REGISTERING = 'registering'
const DECISION_STATUS_FAILED = 'registration_failed'
const DECISION_STATUS_UNREGISTERED = 'unregistered'
const VISIBLE_LEARNING_RECEIPT_STATUSES = new Set(['candidate', 'applied'])
const SERVER_RESOLVABLE_MISSING_FIELDS = new Set(['出行方式'])
const MEMORY_FIELD_ALIASES = {
  application_type: 'applicationType',
  manager_name: 'managerName',
  time_range: 'time',
  transport_mode: 'transportMode'
}

function resolveRefValue(value, fallback = null) {
  if (value && typeof value === 'object' && 'value' in value) {
    return value.value ?? fallback
  }
  return value ?? fallback
}

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

function resolveErrorMessage(error, fallback) {
  return normalizeText(error?.message || error) || fallback
}

function resolveDecisionSourceText(preview = {}, sourceText = '') {
  return normalizeText(
    sourceText
      || preview.decisionSourceText
      || preview.sourceText
      || preview.originalMessage
  )
}

function canResolveApplicationPreviewOnServer(preview = {}) {
  const missingFields = Array.isArray(preview?.missingFields) ? preview.missingFields : []
  const validationIssues = Array.isArray(preview?.validationIssues)
    ? preview.validationIssues
    : []
  return Boolean(
    !validationIssues.length
      && missingFields.length
      && missingFields.every((field) => SERVER_RESOLVABLE_MISSING_FIELDS.has(normalizeText(field)))
  )
}

function resolveApplicationDraftPayload(message = {}, draftClaimId = '', linkedRequest = null) {
  if (message?.draftPayload && typeof message.draftPayload === 'object') {
    return message.draftPayload
  }
  const request = resolveRefValue(linkedRequest, {}) || {}
  const claimId = normalizeText(
    draftClaimId
      || request.claimId
      || request.claim_id
  )
  if (!claimId) return null
  return {
    claim_id: claimId,
    claim_no: normalizeText(request.claimNo || request.claim_no || request.id)
  }
}

export function useTravelReimbursementApplicationPreviewActions({
  conversationId,
  currentUser,
  draftClaimId,
  emitDraftSaved,
  entrySource = 'application',
  confirmForgetMemory = null,
  linkedRequest,
  persistSessionState = () => {},
  reviewActionBusy,
  sessionSwitchBusy,
  submitting,
  toast = () => {}
} = {}) {
  const forgettingApplicationMemoryIds = ref(new Set())

  function resolveApplicationMemoryFieldKey(fieldKey = '') {
    const normalized = normalizeText(fieldKey)
    return MEMORY_FIELD_ALIASES[normalized] || normalized
  }

  function resolveAppliedApplicationPreviewMemories(message) {
    const preview = normalizeApplicationPreview(message?.applicationPreview || {})
    return resolveAiApplicationPreviewMemories(preview).filter((memory) => {
      if (memory.status !== 'applied') return false
      const fieldKey = resolveApplicationMemoryFieldKey(memory.fieldKey)
      return normalizeText(preview.fields?.[fieldKey]) === normalizeText(memory.value)
    })
  }

  function resolveVisibleApplicationLearningReceipts(message) {
    return (Array.isArray(message?.applicationLearningReceipts)
      ? message.applicationLearningReceipts
      : [])
      .map((item) => normalizeAiApplicationMemory(item))
      .filter((item) => item && VISIBLE_LEARNING_RECEIPT_STATUSES.has(item.status))
  }

  function resolveApplicationMemoryEvidenceText(memory = {}) {
    const approvedCount = Number(memory.approvedEvidenceCount || 0)
    const evidenceCount = Number(memory.evidenceCount || 0)
    if (approvedCount > 0) {
      return `${approvedCount} 次已审批记录支持${evidenceCount > approvedCount ? `，共 ${evidenceCount} 次证据` : ''}`
    }
    return evidenceCount > 0 ? `${evidenceCount} 次历史记录支持` : '来自已确认的历史记录'
  }

  function resolveApplicationLearningReceiptTitle(receipt = {}) {
    return receipt.status === 'applied' ? '偏好已激活' : '已记录为候选偏好'
  }

  function isForgettingApplicationMemory(memory = {}) {
    const memoryId = normalizeText(memory.memoryId || memory.memory_id)
    return Boolean(memoryId && forgettingApplicationMemoryIds.value.has(memoryId))
  }

  async function requestForgetMemoryConfirmation(memory) {
    const label = normalizeText(memory?.fieldLabel || memory?.field_label || memory?.fieldKey)
    if (typeof confirmForgetMemory === 'function') {
      return Boolean(await confirmForgetMemory(memory))
    }
    if (typeof globalThis.confirm === 'function') {
      return globalThis.confirm(
        `忘记${label ? `“${label}”` : '此项'}偏好？当前申请中的内容会保留，后续申请不再自动套用。`
      )
    }
    return true
  }

  async function forgetApplicationPreviewMemory(message, memory = {}) {
    const normalizedMemory = normalizeAiApplicationMemory(memory)
    if (!message?.applicationPreview || !normalizedMemory) return false
    if (normalizedMemory.scopeType !== 'user' || normalizedMemory.canRevoke !== true) {
      toast('企业或部门设置由管理员统一维护，当前申请仍可手动修改。')
      return false
    }
    if (isForgettingApplicationMemory(normalizedMemory)) return false
    if (!(await requestForgetMemoryConfirmation(normalizedMemory))) return false

    forgettingApplicationMemoryIds.value = new Set([
      ...forgettingApplicationMemoryIds.value,
      normalizedMemory.memoryId
    ])
    try {
      await forgetAiApplicationMemory(normalizedMemory.memoryId)
      const currentPreview = message.applicationPreview
      const nextMemories = resolveAiApplicationPreviewMemories(currentPreview).filter(
        (item) => item.memoryId !== normalizedMemory.memoryId
      )
      message.applicationPreview = {
        ...currentPreview,
        memoryApplications: nextMemories
      }
      delete message.applicationPreview.memory_applications
      message.applicationLearningReceipts = resolveVisibleApplicationLearningReceipts(message)
        .filter((item) => item.memoryId !== normalizedMemory.memoryId)
      persistSessionState()
      toast('已忘记此偏好，当前申请内容保持不变。')
      return true
    } catch (error) {
      toast(resolveErrorMessage(error, '偏好撤销失败，请稍后重试。'))
      return false
    } finally {
      const nextBusyIds = new Set(forgettingApplicationMemoryIds.value)
      nextBusyIds.delete(normalizedMemory.memoryId)
      forgettingApplicationMemoryIds.value = nextBusyIds
    }
  }

  function isInteractionBusy() {
    return Boolean(
      resolveRefValue(submitting, false)
        || resolveRefValue(reviewActionBusy, false)
        || resolveRefValue(sessionSwitchBusy, false)
    )
  }

  function isRegisteredApplicationPreview(message) {
    const preview = normalizeApplicationPreview(message?.applicationPreview || {})
    return Boolean(
      preview.readyToSubmit
        && normalizeText(preview.decisionId)
        && preview.decisionTrackingStatus === DECISION_STATUS_REGISTERED
    )
  }

  function canSubmitApplicationPreview(message) {
    return isRegisteredApplicationPreview(message)
  }

  function canSaveApplicationPreviewDraft(message) {
    return !isInteractionBusy() && isRegisteredApplicationPreview(message)
  }

  function canRetryApplicationPreviewDecision(message) {
    if (isInteractionBusy() || !message?.applicationPreview) return false
    if (message.applicationSubmitConfirmed) return false
    if (normalizeText(message?.draftPayload?.status) === 'submitted') return false
    const preview = normalizeApplicationPreview(message.applicationPreview)
    return Boolean(
      preview.readyToSubmit
        && !normalizeText(preview.decisionId)
        && [DECISION_STATUS_FAILED, DECISION_STATUS_UNREGISTERED, 'degraded', 'consumed', ''].includes(
          normalizeText(preview.decisionTrackingStatus)
        )
    )
  }

  function buildPendingDecisionPreview(applicationPreview = {}, sourceText = '') {
    const normalized = normalizeApplicationPreview(applicationPreview)
    return normalizeApplicationPreview({
      ...normalized,
      decisionId: '',
      decisionIssueRequestId: normalizeText(normalized.decisionIssueRequestId)
        || createAiApplicationRequestId('preview'),
      decisionActionRequestId: normalizeText(normalized.decisionActionRequestId)
        || createAiApplicationRequestId('action'),
      decisionSourceText: resolveDecisionSourceText(normalized, sourceText),
      decisionTrackingStatus: DECISION_STATUS_REGISTERING,
      decisionRegistrationError: ''
    })
  }

  async function registerApplicationPreviewDecision({
    applicationPreview,
    sourceText = '',
    targetMessage = null,
    preserveCurrentFields = false
  } = {}) {
    const normalized = normalizeApplicationPreview(applicationPreview || {})
    if (!normalized.readyToSubmit && !canResolveApplicationPreviewOnServer(normalized)) {
      return normalizeApplicationPreview({
        ...normalized,
        decisionId: '',
        decisionSourceText: resolveDecisionSourceText(normalized, sourceText),
        decisionTrackingStatus: DECISION_STATUS_UNREGISTERED
      })
    }
    if (
      normalizeText(normalized.decisionId)
        && normalized.decisionTrackingStatus === DECISION_STATUS_REGISTERED
    ) {
      return normalized
    }

    const pendingPreview = buildPendingDecisionPreview(normalized, sourceText)
    if (targetMessage) {
      // 网络请求前先把幂等键写入本地会话；超时或刷新后仍可用同一请求继续签发。
      targetMessage.pendingApplicationPreviewDecision = pendingPreview
      persistSessionState()
    }

    try {
      const registered = await registerAiApplicationPreviewDecision({
        applicationPreview: pendingPreview,
        conversationId: normalizeText(resolveRefValue(conversationId, '')),
        message: pendingPreview.decisionSourceText,
        requestId: pendingPreview.decisionIssueRequestId
      })
      const nextPreview = normalizeApplicationPreview({
        ...registered,
        ...(preserveCurrentFields ? { fields: pendingPreview.fields } : {}),
        decisionIssueRequestId: pendingPreview.decisionIssueRequestId,
        decisionActionRequestId: pendingPreview.decisionActionRequestId,
        decisionSourceText: pendingPreview.decisionSourceText,
        decisionTrackingStatus: DECISION_STATUS_REGISTERED,
        decisionRegistrationError: ''
      })
      if (targetMessage) {
        delete targetMessage.pendingApplicationPreviewDecision
        targetMessage.applicationPreview = nextPreview
        persistSessionState()
      }
      return nextPreview
    } catch (error) {
      const failedPreview = normalizeApplicationPreview({
        ...pendingPreview,
        decisionId: '',
        decisionSource: '',
        decisionExpiresAt: '',
        decisionTrackingStatus: DECISION_STATUS_FAILED,
        decisionRegistrationError: resolveErrorMessage(error, '服务端暂未完成申请预览签发。')
      })
      if (targetMessage) {
        delete targetMessage.pendingApplicationPreviewDecision
        targetMessage.applicationPreview = failedPreview
        persistSessionState()
      }
      return failedPreview
    }
  }

  async function retryApplicationPreviewDecision(message) {
    if (!canRetryApplicationPreviewDecision(message)) return false
    reviewActionBusy.value = true
    try {
      const preview = await registerApplicationPreviewDecision({
        applicationPreview: message.applicationPreview,
        sourceText: resolveDecisionSourceText(message.applicationPreview),
        targetMessage: message,
        preserveCurrentFields: true
      })
      if (preview.decisionTrackingStatus === DECISION_STATUS_REGISTERED) {
        message.text = message.text || ''
        toast('申请预览已重新签发，可以保存或提交。')
        return true
      }
      toast(preview.decisionRegistrationError || '申请预览签发失败，请稍后重试。')
      return false
    } finally {
      reviewActionBusy.value = false
      persistSessionState()
    }
  }

  async function runApplicationPreviewAction(actionType, message) {
    if (!message?.applicationPreview) {
      throw new Error('当前没有可处理的申请预览。')
    }
    let preview = normalizeApplicationPreview(message.applicationPreview)
    if (!preview.readyToSubmit) {
      throw new Error(`请先补充：${preview.missingFields.join('、') || '申请必填信息'}。`)
    }
    if (
      !normalizeText(preview.decisionId)
        || preview.decisionTrackingStatus !== DECISION_STATUS_REGISTERED
    ) {
      // structured preview 必须持有服务端签发结果，禁止降级为客户端观察动作。
      throw new Error('申请预览尚未通过服务端签发，请先点击“重新签发”。')
    }

    const actionRequestId = normalizeText(preview.decisionActionRequestId)
      || createAiApplicationRequestId('action')
    preview = normalizeApplicationPreview({
      ...preview,
      decisionActionRequestId: actionRequestId
    })
    message.applicationPreview = preview
    persistSessionState()

    let payload
    try {
      payload = await runAiApplicationPreviewAction({
        actionType,
        applicationPreview: preview,
        currentUser: resolveRefValue(currentUser, {}) || {},
        conversationId: normalizeText(resolveRefValue(conversationId, '')),
        draftPayload: resolveApplicationDraftPayload(
          message,
          normalizeText(resolveRefValue(draftClaimId, '')),
          linkedRequest
        ),
        requestId: actionRequestId,
        entrySource: normalizeText(entrySource) || 'application',
        source: 'financial_assistant'
      })
    } catch (error) {
      const errorText = resolveErrorMessage(error, '申请动作执行失败。')
      if (/已过期|已被.*消费|不可使用|不存在或不属于|重新生成预览/.test(errorText)) {
        message.applicationPreview = normalizeApplicationPreview({
          ...preview,
          decisionId: '',
          decisionSource: '',
          decisionExpiresAt: '',
          decisionTrackingStatus: DECISION_STATUS_FAILED,
          decisionRegistrationError: `${errorText} 请重新签发后继续。`,
          decisionIssueRequestId: createAiApplicationRequestId('preview'),
          decisionActionRequestId: ''
        })
        persistSessionState()
      }
      throw error
    }
    const result = payload?.result && typeof payload.result === 'object' ? payload.result : {}
    message.applicationLearningReceipts = resolveAiApplicationLearningReceipts(payload)
    const nextDraftPayload = result.draft_payload && typeof result.draft_payload === 'object'
      ? result.draft_payload
      : null
    if (nextDraftPayload) {
      message.draftPayload = nextDraftPayload
      const nextClaimId = normalizeText(nextDraftPayload.claim_id || nextDraftPayload.claimId)
      if (nextClaimId && draftClaimId && typeof draftClaimId === 'object' && 'value' in draftClaimId) {
        draftClaimId.value = nextClaimId
      }
    }

    const nextDecisionId = normalizeText(result.decision_id)
    const isSaveDraft = actionType === AI_APPLICATION_ACTION_SAVE_DRAFT
    message.applicationPreview = normalizeApplicationPreview({
      ...preview,
      decisionId: nextDecisionId,
      decisionSource: nextDecisionId ? 'server_draft' : '',
      decisionExpiresAt: normalizeText(result.decision_expires_at),
      decisionTrackingStatus: nextDecisionId
        ? DECISION_STATUS_REGISTERED
        : isSaveDraft
          ? DECISION_STATUS_FAILED
          : 'consumed',
      decisionRegistrationError: isSaveDraft && !nextDecisionId
        ? '草稿已保存，但后续申请预览签发失败，请重新签发后再提交。'
        : '',
      decisionIssueRequestId: isSaveDraft && !nextDecisionId
        ? createAiApplicationRequestId('preview')
        : '',
      decisionActionRequestId: nextDecisionId ? createAiApplicationRequestId('action') : ''
    })
    persistSessionState()
    return payload
  }

  async function saveApplicationPreviewDraft(message) {
    if (!canSaveApplicationPreviewDraft(message)) return null
    reviewActionBusy.value = true
    try {
      const payload = await runApplicationPreviewAction(
        AI_APPLICATION_ACTION_SAVE_DRAFT,
        message
      )
      const draftPayload = payload?.result?.draft_payload || {}
      const claimId = normalizeText(draftPayload.claim_id || draftPayload.claimId)
      const claimNo = normalizeText(draftPayload.claim_no || draftPayload.claimNo)
      if (claimId || claimNo) {
        emitDraftSaved?.({
          claimId,
          claimNo,
          status: 'draft',
          approvalStage: normalizeText(draftPayload.approval_stage) || '待提交',
          documentType: 'application'
        })
      }
      toast('申请草稿已保存。')
      return payload
    } catch (error) {
      toast(resolveErrorMessage(error, '申请草稿保存失败，请稍后重试。'))
      return null
    } finally {
      reviewActionBusy.value = false
      persistSessionState()
    }
  }

  return {
    canRetryApplicationPreviewDecision,
    canSaveApplicationPreviewDraft,
    canSubmitApplicationPreview,
    forgetApplicationPreviewMemory,
    isForgettingApplicationMemory,
    registerApplicationPreviewDecision,
    resolveApplicationLearningReceiptTitle,
    resolveApplicationMemoryEvidenceText,
    resolveAppliedApplicationPreviewMemories,
    resolveVisibleApplicationLearningReceipts,
    retryApplicationPreviewDecision,
    runApplicationPreviewAction,
    saveApplicationPreviewDraft
  }
}

export {
  AI_APPLICATION_ACTION_SAVE_DRAFT,
  AI_APPLICATION_ACTION_SUBMIT
}
