import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

import { useNavigation, navItems } from './useNavigation.js'
import { mapExpenseClaimToRequest, useRequests } from './useRequests.js'
import { useSystemState } from './useSystemState.js'
import { useToast } from './useToast.js'
import {
  REIMBURSEMENT_LIST_PREVIEW_PARAMS,
  extractExpenseClaimItems,
  fetchApprovalExpenseClaims,
  fetchExpenseClaimDetail
} from '../services/reimbursements.js'
import { fetchOntologyParse } from '../services/ontology.js'
import { fetchLatestConversation } from '../services/orchestrator.js'
import { markAiWorkbenchConversationDraftDeleted } from '../utils/aiWorkbenchConversationStore.js'
import { clearAssistantSessionSnapshotForDraftClaim } from '../utils/assistantSessionSnapshot.js'
import { isApplicationDocumentNo } from '../utils/documentClassification.js'
import {
  ASSISTANT_SCOPE_SESSION_STEWARD,
  buildUnsupportedBusinessScopeConversation,
  resolveAssistantScopeGuard
} from '../utils/assistantSessionScope.js'
import { buildDetailAlerts } from '../utils/detailAlerts.js'
import { normalizeRequestForUi } from '../utils/requestViewModel.js'
import {
  buildWorkbenchIntentOntologyContext,
  resolveWorkbenchSessionTypeFallback,
  resolveWorkbenchSessionTypeFromOntology
} from '../utils/workbenchAssistantIntent.js'
import { buildWorkbenchSummary } from '../utils/workbenchSummary.js'
import { createCurrentYearDateRange } from '../utils/dateRangeDefaults.js'

const SESSION_TYPE_EXPENSE = 'expense'
const SMART_ENTRY_SOURCE_APPLICATION = 'application'
const SMART_ENTRY_SOURCE_REIMBURSEMENT = 'topbar'
const DOCUMENT_DETAIL_RETURN_TARGETS = new Set(['workbench', 'conversation', 'value'])

function resolveDocumentDetailReturnTarget(value) {
  const target = String(value || '').trim()
  return DOCUMENT_DETAIL_RETURN_TARGETS.has(target) ? target : ''
}

export function useAppShell() {
  const route = useRoute()
  const router = useRouter()

  const smartEntryOpen = ref(false)
  const smartEntryContext = ref({
    prompt: '',
    source: 'documents',
    request: null,
    files: [],
    conversation: null,
    scope: null,
    sessionType: '',
    budgetContext: null,
    initialPromptAutoSubmit: true,
    initialApplicationPreview: null,
    initialDraftPayload: null
  })
  const smartEntrySessionId = ref(0)
  const smartEntryRevealToken = ref(0)
  const smartEntryInvalidatedDraftClaimId = ref('')
  const selectedRequestSnapshot = ref(null)
  const documentCenterRefreshToken = ref(0)
  const workbenchApprovalRequests = ref([])

  const { activeView, currentView, setView } = useNavigation()
  const {
    requests,
    loading: requestsLoading,
    error: requestsError,
    search,
    filters,
    ranges,
    activeRange,
    filteredRequests,
    approveRequest,
    rejectRequest,
    ensureLoaded: ensureRequestsLoaded,
    reload: reloadRequests
  } = useRequests()
  const { currentUser } = useSystemState()
  const { toast } = useToast()

  const customRange = ref(createCurrentYearDateRange())
  const workbenchRequests = computed(() =>
    mergeWorkbenchRequests(requests.value, workbenchApprovalRequests.value)
  )

  const selectedRequest = computed(() => {
    const requestId = String(route.params.requestId || '')

    if (!requestId) {
      return null
    }

    const snapshot = normalizeRequestForUi(selectedRequestSnapshot.value)
    if (isSameRequestIdentity(snapshot, requestId)) {
      return snapshot
    }

    const rawRequest = workbenchRequests.value.find((item) => isSameRequestIdentity(item, requestId))
    const normalizedRequest = normalizeRequestForUi(rawRequest)
    if (normalizedRequest) {
      return normalizedRequest
    }

    return null
  })

  const detailMode = computed(() => route.name === 'app-document-detail')
  const detailReturnTarget = computed(() => resolveDocumentDetailReturnTarget(route.query.returnTo))
  const detailBackLabel = computed(() => {
    if (detailReturnTarget.value === 'conversation') {
      return '返回对话'
    }
    if (detailReturnTarget.value === 'workbench') return '返回首页'
    return detailReturnTarget.value === 'value' ? '返回经营价值' : '返回单据中心'
  })
  const detailAlerts = computed(() => (
    detailMode.value
      ? buildDetailAlerts(selectedRequest.value, { currentUser: currentUser.value })
      : []
  ))

  async function reloadDocumentCenterRequests() {
    documentCenterRefreshToken.value += 1
    return reloadRequests()
  }

  async function reloadWorkbenchApprovalRequests() {
    try {
      const payload = await fetchApprovalExpenseClaims(REIMBURSEMENT_LIST_PREVIEW_PARAMS)
      workbenchApprovalRequests.value = extractExpenseClaimItems(payload).map((item) => mapExpenseClaimToRequest(item))
    } catch {
      workbenchApprovalRequests.value = []
    }
  }

  async function reloadWorkbenchRequests() {
    const [payload] = await Promise.all([
      reloadRequests({ silent: true }),
      reloadWorkbenchApprovalRequests()
    ])
    return payload
  }

  function resolveWorkbenchRequestKey(request) {
    return String(request?.claimId || request?.id || request?.claimNo || '').trim()
  }

  function mergeWorkbenchRequests(primaryRequests = [], approvalRequests = []) {
    const merged = new Map()
    for (const request of [...primaryRequests, ...approvalRequests]) {
      const key = resolveWorkbenchRequestKey(request)
      if (key) {
        merged.set(key, request)
      }
    }
    return Array.from(merged.values())
  }

  function isSameRequestIdentity(request, requestId) {
    const normalizedId = String(requestId || '').trim()
    if (!request || !normalizedId) {
      return false
    }
    return [
      request.claimId,
      request.id,
      request.claimNo,
      request.documentNo
    ].some((value) => String(value || '').trim() === normalizedId)
  }

  function isDetailLookupOnlyPayload(payload = {}) {
    return Boolean(payload?.detailLookupOnly || payload?.detail_lookup_only)
  }

  function resolveRequestDetailLookupId(requestOrId = selectedRequestSnapshot.value) {
    if (typeof requestOrId === 'string') {
      return requestOrId.trim()
    }
    return String(
      requestOrId?.claimId
      || requestOrId?.claim_id
      || requestOrId?.id
      || requestOrId?.claimNo
      || requestOrId?.claim_no
      || requestOrId?.documentNo
      || requestOrId?.document_no
      || ''
    ).trim()
  }

  function upsertRequestSnapshot(nextRequest) {
    if (!nextRequest) {
      return
    }
    selectedRequestSnapshot.value = nextRequest
    const nextIdValues = [
      nextRequest.claimId,
      nextRequest.id,
      nextRequest.claimNo,
      nextRequest.documentNo
    ].map((item) => String(item || '').trim()).filter(Boolean)
    const nextIdSet = new Set(nextIdValues)
    const index = requests.value.findIndex((item) => [
      item.claimId,
      item.id,
      item.claimNo,
      item.documentNo
    ].some((value) => nextIdSet.has(String(value || '').trim())))
    if (index >= 0) {
      requests.value.splice(index, 1, nextRequest)
    }
  }

  async function refreshSelectedRequestDetail(requestOrId = selectedRequestSnapshot.value) {
    const lookupId = resolveRequestDetailLookupId(requestOrId)
    if (!lookupId) {
      return
    }
    try {
      const payload = await fetchExpenseClaimDetail(lookupId)
      const mappedRequest = mapExpenseClaimToRequest(payload)
      const routeRequestId = String(route.params.requestId || '').trim()
      if (!routeRequestId || isSameRequestIdentity(mappedRequest, routeRequestId) || routeRequestId === lookupId) {
        upsertRequestSnapshot(mappedRequest)
      }
    } catch {
      // 保留当前快照，避免详情刷新失败时把页面置空。
    }
  }

  watch(
    () => [activeView.value, route.name],
    ([view]) => {
      if (route.name === 'app-document-detail') {
        void ensureRequestsLoaded()
        void refreshSelectedRequestDetail(String(route.params.requestId || ''))
        return
      }
      if (view === 'documents') {
        void reloadDocumentCenterRequests()
        return
      }
      if (view === 'workbench') {
        void reloadWorkbenchRequests()
      }
    },
    { immediate: true }
  )

  const workbenchSummary = computed(() =>
    buildWorkbenchSummary(workbenchRequests.value, currentUser.value)
  )

  const topBarView = computed(() => {
    if (detailMode.value) {
      const request = selectedRequest.value || {}
      const claimNo = request.claimNo || request.claim_no || request.documentNo || request.id || ''
      const isApplicationDocument = isApplicationDocumentPayload(request, claimNo)
      return {
        title: isApplicationDocument ? '申请单详情' : '报销单详情',
        desc: isApplicationDocument
          ? '查看申请信息、预计金额与审批进度。'
          : '查看报销明细、票据材料、审批进度与风险提示。'
      }
    }

    return currentView.value
  })

  const requestSummary = computed(() =>
    filteredRequests.value.reduce(
      (summary, item) => {
        const request = normalizeRequestForUi(item)
        if (!request) {
          return summary
        }

        summary.total += 1

        if (request.approvalKey === 'draft') {
          summary.draft += 1
        } else if (request.approvalKey === 'in_progress') {
          summary.inProgress += 1
        } else if (request.approvalKey === 'supplement') {
          summary.supplement += 1
        } else if (request.approvalKey === 'completed') {
          summary.completed += 1
        }

        return summary
      },
      { total: 0, draft: 0, inProgress: 0, supplement: 0, completed: 0 }
    )
  )

  function handleApprove(request) {
    const message = approveRequest(request)
    toast(message)
  }

  function handleReject(request) {
    const message = rejectRequest(request)
    toast(message)
  }

  function handleNavigate(view) {
    smartEntryOpen.value = false
    const shouldRefreshCurrentDocumentCenter =
      view === 'documents'
      && activeView.value === 'documents'
      && route.name === 'app-documents'
    const navigation = setView(view)
    if (shouldRefreshCurrentDocumentCenter) {
      void reloadDocumentCenterRequests()
    }
    return navigation
  }

  function openFinancialAssistantCreate(source) {
    if (smartEntryOpen.value) {
      smartEntryRevealToken.value += 1
      return
    }
    smartEntryOpen.value = true
    smartEntryContext.value = {
      prompt: '',
      source,
      request: null,
      files: [],
      conversation: null,
      scope: null,
      sessionType: '',
      budgetContext: null,
      initialPromptAutoSubmit: true,
      initialApplicationPreview: null,
      initialDraftPayload: null
    }
    smartEntrySessionId.value += 1
  }

  function openTravelCreate() {
    openFinancialAssistantCreate(SMART_ENTRY_SOURCE_REIMBURSEMENT)
  }

  function openExpenseApplicationCreate() {
    openFinancialAssistantCreate(SMART_ENTRY_SOURCE_APPLICATION)
  }

  function resolveCurrentUserId() {
    const user = currentUser.value || {}
    return String(user.username || user.name || 'anonymous').trim() || 'anonymous'
  }

  function resolveSmartEntryClaimScope(payload = {}) {
    const request = payload.request && typeof payload.request === 'object' ? payload.request : null
    const payloadScope = payload.scope && typeof payload.scope === 'object' ? payload.scope : null
    const claimId = String(
      payloadScope?.claimId ||
        payloadScope?.claim_id ||
        request?.claimId ||
        request?.claim_id ||
        ''
    ).trim()
    if (!claimId) {
      return null
    }
    return { type: 'claim', claimId }
  }

  function isDetailClaimScopedPayload(payload = {}) {
    return String(payload.source || '').trim() === 'detail' && Boolean(resolveSmartEntryClaimScope(payload))
  }

  async function resolveSmartEntrySessionType(payload = {}) {
    const explicitSessionType = String(payload.sessionType || '').trim()
    if (explicitSessionType) {
      return explicitSessionType
    }

    const source = String(payload.source || 'workbench').trim()
    if (source !== 'workbench') {
      return ''
    }

    const prompt = String(payload.prompt || '').trim()
    const files = Array.isArray(payload.files) ? payload.files : []
    const fallbackSessionType = resolveWorkbenchSessionTypeFallback(prompt, {
      attachmentCount: files.length
    })
    if (!prompt) {
      return fallbackSessionType
    }
    if (fallbackSessionType === ASSISTANT_SCOPE_SESSION_STEWARD) {
      return fallbackSessionType
    }

    try {
      const ontology = await fetchOntologyParse(
        {
          query: prompt,
          user_id: resolveCurrentUserId(),
          context_json: {
            ...buildWorkbenchIntentOntologyContext({
              currentUser: currentUser.value,
              files
            }),
            user_input_text: prompt,
            fallback_session_type: fallbackSessionType
          }
        },
        {
          timeoutMs: 12000,
          timeoutMessage: '意图识别超时，已使用本地规则进入助手。'
        }
      )
      return resolveWorkbenchSessionTypeFromOntology(ontology, prompt, fallbackSessionType)
    } catch (error) {
      console.warn('Workbench model intent routing failed, fallback to local routing:', error)
      return fallbackSessionType
    }
  }

  function isApplicationDocumentPayload(payload = {}, claimNo = '') {
    const documentType = String(
      payload.documentType
      || payload.document_type
      || payload.documentTypeCode
      || payload.document_type_code
      || payload.draftType
      || payload.draft_type
      || ''
    ).trim()
    const normalizedClaimNo = String(claimNo || payload.claimNo || payload.claim_no || '').trim().toUpperCase()
    return (
      documentType === 'application'
      || documentType === 'expense_application'
      || isApplicationDocumentNo(normalizedClaimNo)
    )
  }

  async function resolveSmartEntryConversation(payload = {}) {
    if (payload.conversation) {
      return payload.conversation
    }

    if (isDetailClaimScopedPayload(payload)) {
      return null
    }

    if (!payload.restoreLatestConversation) {
      return null
    }

    try {
      const latestPayload = await fetchLatestConversation(resolveCurrentUserId(), SESSION_TYPE_EXPENSE, {
        preferRecoverable: true
      })
      return latestPayload?.found ? latestPayload.conversation || null : null
    } catch (error) {
      console.warn('Failed to restore latest expense conversation for smart entry:', error)
      toast(error?.message || '恢复最近报销会话失败，请稍后重试。')
      return null
    }
  }

  async function openSmartEntry(payload = {}) {
    const shouldReplaceOpenEntry = Boolean(
      payload?.source === 'budget'
        || payload?.sessionType
        || String(payload?.prompt || '').trim()
        || (Array.isArray(payload?.files) && payload.files.length)
        || payload?.conversation
        || payload?.applicationPreview
    )
    if (smartEntryOpen.value && !shouldReplaceOpenEntry) {
      smartEntryRevealToken.value += 1
      return
    }

    const prompt = String(payload.prompt || '').trim()
    const files = Array.isArray(payload.files) ? payload.files : []
    const scopeGuard = prompt
      ? resolveAssistantScopeGuard(prompt, String(payload.sessionType || '').trim(), {
          attachmentCount: files.length
        })
      : null
    if (scopeGuard?.blocked) {
      smartEntryOpen.value = true
      smartEntryContext.value = {
        prompt: '',
        source: payload.source ?? 'workbench',
        request: payload.request ?? selectedRequest.value,
        files,
        conversation: buildUnsupportedBusinessScopeConversation(prompt, {
          attachmentCount: files.length
        }),
        scope: null,
        sessionType: ASSISTANT_SCOPE_SESSION_STEWARD,
        budgetContext: payload.budgetContext && typeof payload.budgetContext === 'object'
          ? payload.budgetContext
          : null,
        initialPromptAutoSubmit: false,
        initialApplicationPreview: null,
        initialDraftPayload: null
      }
      smartEntrySessionId.value += 1
      return
    }

    const [conversation, sessionType] = await Promise.all([
      resolveSmartEntryConversation(payload),
      resolveSmartEntrySessionType(payload)
    ])
    const scope = resolveSmartEntryClaimScope(payload)
    smartEntryOpen.value = true

    smartEntryContext.value = {
      prompt: payload.prompt ?? '',
      source: payload.source ?? 'workbench',
      request: payload.request ?? selectedRequest.value,
      files: Array.isArray(payload.files) ? payload.files : [],
      conversation,
      scope,
      sessionType,
      budgetContext: payload.budgetContext && typeof payload.budgetContext === 'object'
        ? payload.budgetContext
        : null,
      initialPromptAutoSubmit: payload.initialPromptAutoSubmit !== false,
      initialApplicationPreview: payload.applicationPreview && typeof payload.applicationPreview === 'object'
        ? payload.applicationPreview
        : null,
      initialDraftPayload: payload.draftPayload && typeof payload.draftPayload === 'object'
        ? payload.draftPayload
        : null
    }
    smartEntrySessionId.value += 1
  }

  function closeSmartEntry() {
    smartEntryOpen.value = false
  }

  async function handleDraftSaved(payload = {}) {
    const claimNo = String(payload.claimNo || payload.claim_no || '').trim()
    const status = String(payload.status || payload.claimStatus || '').trim()
    const approvalStage = String(payload.approvalStage || payload.approval_stage || '').trim()
    const isApplicationDocument = isApplicationDocumentPayload(payload, claimNo)
    await reloadWorkbenchRequests()
    if (status === 'submitted') {
      if (isApplicationDocument) {
        toast(`${claimNo || '该'}申请单已提交${approvalStage ? `，当前节点：${approvalStage}` : '，等待直属领导审批'}。`)
        return
      }
      smartEntryOpen.value = false
      toast(`${claimNo || '该'}单据已提交审批${approvalStage ? `，当前节点：${approvalStage}` : '。'}`)
      router.push({ name: 'app-documents' })
      return
    }
    toast(
      isApplicationDocument
        ? `${claimNo || '该'}申请单已保存为草稿，可继续补充申请信息。`
        : `${claimNo || '该'}单据已保存为草稿，可继续上传票据或补充信息。`
    )
  }

  function buildDocumentDetailQuery(options = {}) {
    const nextQuery = { ...route.query }
    const returnTo = resolveDocumentDetailReturnTarget(options.returnTo)
    if (returnTo) {
      nextQuery.returnTo = returnTo
    } else {
      delete nextQuery.returnTo
    }
    return nextQuery
  }

  function buildDocumentReturnQuery() {
    const { returnTo, ...nextQuery } = route.query
    return nextQuery
  }

  function buildValueDashboardReturnQuery() {
    const nextQuery = {}
    Object.entries(buildDocumentReturnQuery()).forEach(([key, value]) => {
      if (['range', 'start', 'end'].includes(key) || key.startsWith('value_')) {
        nextQuery[key] = value
      }
    })
    nextQuery.dashboard = 'value'
    return nextQuery
  }

  function openRequestDetail(request, options = {}) {
    const requestId = resolveRequestDetailLookupId(request)
    if (!requestId) {
      return
    }
    const isDetailLookupOnlyRequest = isDetailLookupOnlyPayload(request)
    selectedRequestSnapshot.value = isDetailLookupOnlyRequest ? null : request || null
    router.push({
      name: 'app-document-detail',
      params: { requestId },
      query: buildDocumentDetailQuery(options)
    })
    void refreshSelectedRequestDetail(isDetailLookupOnlyRequest ? requestId : request)
  }

  function closeRequestDetail() {
    if (detailReturnTarget.value === 'conversation') {
      return router.push({ name: 'app-workbench' })
    }

    if (detailReturnTarget.value === 'workbench') {
      return router.push({ name: 'app-workbench' })
    }

    if (detailReturnTarget.value === 'value') {
      return router.push({ name: 'app-overview', query: buildValueDashboardReturnQuery() })
    }

    return router.push({ name: 'app-documents', query: buildDocumentReturnQuery() })
  }

  async function handleRequestUpdated(payload = {}) {
    if (payload?.claim && typeof payload.claim === 'object') {
      const mappedRequest = mapExpenseClaimToRequest(payload.claim)
      upsertRequestSnapshot(mappedRequest)
    }
    const claimId = String(payload?.claimId || payload?.claim_id || route.params.requestId || '').trim()
    await reloadWorkbenchRequests()
    await refreshSelectedRequestDetail(claimId)
  }

  async function handleRequestDeleted(payload = {}) {
    const deletedClaimId = String(payload.claimId || payload.claim_id || '').trim()
    if (deletedClaimId) {
      clearAssistantSessionSnapshotForDraftClaim(resolveCurrentUserId(), deletedClaimId, SESSION_TYPE_EXPENSE)
      markAiWorkbenchConversationDraftDeleted(currentUser.value || {}, payload)
      smartEntryInvalidatedDraftClaimId.value = deletedClaimId
    }

    await reloadRequests()
    selectedRequestSnapshot.value = null
    router.push({ name: 'app-documents', query: buildDocumentReturnQuery() })
  }

  return {
    activeRange,
    activeView,
    closeRequestDetail,
    closeSmartEntry,
    currentView,
    customRange,
    detailMode,
    documentCenterRefreshToken,
    filteredRequests,
    filters,
    handleApprove,
    handleDraftSaved,
    handleNavigate,
    handleReject,
    handleRequestDeleted,
    handleRequestUpdated,
    navItems,
    openExpenseApplicationCreate,
    openRequestDetail,
    openSmartEntry,
    openTravelCreate,
    ranges,
    requestSummary,
    workbenchRequests,
    workbenchSummary,
    requestsError,
    requestsLoading,
    reloadRequests,
    reloadDocumentCenterRequests,
    requests,
    search,
    selectedRequest,
    setView,
    smartEntryContext,
    smartEntryInvalidatedDraftClaimId,
    smartEntryOpen,
    smartEntryRevealToken,
    smartEntrySessionId,
    detailAlerts,
    detailBackLabel,
    detailReturnTarget,
    toast,
    topBarView
  }
}
