<template>
  <div
    class="app"
    :class="{
      'sidebar-collapsed': sidebarCollapsed,
      'workbench-ai-sidebar-active': isAiShellMode,
      'mobile-sidebar-open': mobileSidebarOpen
    }"
  >
    <div class="mobile-overlay" aria-hidden="true" @click="mobileSidebarOpen = false"></div>
    <button
      type="button"
      class="mobile-hamburger-btn"
      aria-label="打开移动端导航"
      :aria-expanded="mobileSidebarOpen ? 'true' : 'false'"
      @click="mobileSidebarOpen = true"
    >
      <i class="mdi mdi-menu" aria-hidden="true"></i>
    </button>
    <div class="app-sidebar">
      <Transition name="sidebar-mode-fade" mode="out-in">
        <AiSidebarRail
          v-if="isAiShellMode"
          key="ai-sidebar"
          :nav-items="filteredNavItems"
          :active-view="activeView"
          :active-conversation-id="aiActiveConversationId"
          :conversation-history="aiConversationHistory"
          :current-user="currentUser"
          :brand-name="PRODUCT_DISPLAY_NAME"
          :brand-logo="companyProfile.logo"
          :collapsed="sidebarCollapsed"
          @navigate="handleNavigateWithMobileClose"
          @new-chat="openAiSidebarNewChat"
          @open-recent="openAiSidebarRecent"
          @rename-conversation="handleAiConversationRename"
          @prefetch-view="prefetchAppView"
          @logout="handleLogout"
        />
        <SidebarRail
          v-else
          key="standard-sidebar"
          :nav-items="filteredNavItems"
          :active-view="activeView"
          :company-name="PRODUCT_DISPLAY_NAME"
          :company-logo="companyProfile.logo"
          :current-user="currentUser"
          :collapsed="sidebarCollapsed"
          @open-chat="openSmartEntry"
          @logout="handleLogout"
          @toggle-collapse="toggleSidebarCollapsed"
          @navigate="handleNavigateWithMobileClose"
          @prefetch-view="prefetchAppView"
        />
      </Transition>
    </div>

    <main
      class="main"
      :class="{
        'overview-main': activeView === 'overview',
        'workbench-main': activeView === 'workbench',
        'documents-main': activeView === 'documents',
        'receipt-folder-main': activeView === 'receiptFolder',
        'budget-main': activeView === 'budget',
        'policies-main': activeView === 'policies',
        'audit-main': activeView === 'audit',
        'audit-detail-main': activeView === 'audit' && auditDetailOpen,
        'digital-employees-detail-main': activeView === 'digitalEmployees' && digitalEmployeeDetailOpen,
        'digital-employees-main': activeView === 'digitalEmployees',
        'employees-main': activeView === 'employees',
        'settings-main': activeView === 'settings'
      }"
    >
      <TopBar
        v-if="activeView !== 'settings'"
        :current-view="resolvedTopBarView"
        :search="search"
        :active-view="activeView"
        :ranges="ranges"
        :active-range="activeRange"
        :employee-summary="employeeSummary"
        :knowledge-summary="knowledgeSummary"
        :request-summary="requestSummary"
        :document-summary="documentSummary"
        :workbench-summary="workbenchSummary"
        :workbench-mode="workbenchMode"
        :digital-employee-summary="digitalEmployeeSummary"
        :company-name="ENTERPRISE_DISPLAY_NAME"
        :detail-mode="resolvedDetailMode"
        :detail-alerts="resolvedDetailAlerts"
        :detail-kpis="resolvedDetailKpis"
        :custom-range="customRange"
        :overview-dashboard="overviewDashboard"
        @update:search="search = $event"
        @update:active-range="activeRange = $event"
        @update:custom-range="customRange = $event"
        @update:overview-dashboard="overviewDashboard = $event"
        @new-application="openExpenseApplicationCreate"
        @open-document="openWorkbenchDocument"
        @navigate="handleNavigate"
        @toggle-workbench-mode="toggleWorkbenchMode"
      />

      <FilterBar
        v-if="activeView !== 'overview' && activeView !== 'workbench' && activeView !== 'documents' && activeView !== 'receiptFolder' && activeView !== 'budget' && activeView !== 'policies' && activeView !== 'audit' && activeView !== 'digitalEmployees' && activeView !== 'employees' && activeView !== 'settings'"
        :compact="activeView === 'overview'"
        :filters="filters"
        :ranges="ranges"
        :active-range="activeRange"
        @update:active-range="activeRange = $event"
      />

      <section
        class="workarea"
        :class="{
          'documents-workarea': activeView === 'documents',
          'receipt-folder-workarea': activeView === 'receiptFolder',
          'workbench-workarea': activeView === 'workbench',
          'workbench-workarea-ai-mode': isWorkbenchAiMode,
          'budget-workarea': activeView === 'budget',
          'policies-workarea': activeView === 'policies',
          'audit-workarea': activeView === 'audit',
          'digital-employees-workarea': activeView === 'digitalEmployees',
          'employees-workarea': activeView === 'employees',
          'settings-workarea': activeView === 'settings'
        }"
      >
        <OverviewView
          v-if="activeView === 'overview'"
          :filtered-requests="filteredRequests"
          :dashboard="overviewDashboard"
          :current-user="currentUser"
          :active-range="activeRange"
          :custom-range="customRange"
          @approve="handleApprove"
          @reject="handleReject"
        />

        <PersonalWorkbenchView
          v-else-if="activeView === 'workbench'"
          :assistant-modal-open="smartEntryOpen"
          :workbench-summary="workbenchSummary"
          :workbench-mode="workbenchMode"
          :ai-sidebar-command="aiSidebarCommand"
          @ai-conversation-change="handleAiConversationChange"
          @ai-conversation-history-change="handleAiConversationHistoryChange"
          @open-assistant="openSmartEntry"
          @open-document="openWorkbenchDocument"
          @request-updated="handleRequestUpdated"
        />

        <TravelRequestDetailView
          v-else-if="activeView === 'documents' && detailMode && selectedRequest"
          :request="selectedRequest"
          :back-label="detailBackLabel"
          @back-to-requests="handleDocumentDetailBack"
          @open-assistant="openSmartEntry"
          @request-updated="handleRequestUpdated"
          @request-deleted="handleDetailRequestDeleted"
        />

        <section
          v-else-if="activeView === 'documents' && detailMode && !selectedRequest"
          class="document-detail-loading panel"
          aria-live="polite"
        >
          <i class="mdi mdi-loading mdi-spin" aria-hidden="true"></i>
          <div>
            <strong>正在加载完整单据详情</strong>
            <p>正在读取申请表、审批进度和详情字段，加载完成后再展示详情表格。</p>
          </div>
        </section>

        <DocumentsCenterView
          v-else-if="activeView === 'documents'"
          :filtered-requests="requests"
          :has-data="requests.length > 0"
          :loading="requestsLoading"
          :error="requestsError"
          :refresh-token="documentCenterRefreshToken"
          @open-document="openRequestDetail"
          @create-request="openTravelCreate"
          @create-application="openExpenseApplicationCreate"
          @reload="reloadRequests"
          @request-updated="handleRequestUpdated"
          @summary-change="documentSummary = $event"
        />

        <ReceiptFolderView
          v-else-if="activeView === 'receiptFolder'"
          @open-assistant="openSmartEntry"
          @detail-open-change="receiptFolderDetailOpen = $event"
          @detail-topbar-change="detailTopBarPayload = $event"
        />

        <BudgetCenterView
          v-else-if="activeView === 'budget'"
          :current-user="currentUser"
          @open-assistant="openSmartEntry"
          @detail-open-change="budgetDetailOpen = $event"
          @detail-topbar-change="detailTopBarPayload = $event"
        />
        <PoliciesView v-else-if="activeView === 'policies'" @summary-change="knowledgeSummary = $event" />
        <AuditView
          v-else-if="activeView === 'audit'"
          @detail-open-change="auditDetailOpen = $event"
          @detail-topbar-change="detailTopBarPayload = $event"
        />
        <DigitalEmployeesView
          v-else-if="activeView === 'digitalEmployees'"
          @summary-change="digitalEmployeeSummary = $event"
          @detail-open-change="digitalEmployeeDetailOpen = $event"
          @detail-topbar-change="detailTopBarPayload = $event"
        />
        <EmployeeManagementView v-else-if="activeView === 'employees'" @overview-change="employeeSummary = $event" />
        <SettingsView v-else />
      </section>
    </main>

    <TravelReimbursementCreateView
      v-if="smartEntryOpen"
      :key="smartEntrySessionId"
      :initial-prompt="smartEntryContext.prompt"
      :initial-files="smartEntryContext.files"
      :initial-conversation="smartEntryContext.conversation"
      :initial-session-type="smartEntryContext.sessionType"
      :initial-budget-context="smartEntryContext.budgetContext"
      :initial-prompt-auto-submit="smartEntryContext.initialPromptAutoSubmit"
      :initial-application-preview="smartEntryContext.initialApplicationPreview"
      :initial-draft-payload="smartEntryContext.initialDraftPayload"
      :entry-source="smartEntryContext.source"
      :request-context="smartEntryContext.request"
      :invalidated-draft-claim-id="smartEntryInvalidatedDraftClaimId"
      :reopen-token="smartEntryRevealToken"
      @close="closeSmartEntry"
      @draft-saved="handleDraftSaved"
      @request-updated="handleRequestUpdated"
    />
  </div>
</template>

<script setup>
import { computed, nextTick, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

import AiSidebarRail from '../components/layout/AiSidebarRail.vue'
import SidebarRail from '../components/layout/SidebarRail.vue'
import TopBar from '../components/layout/TopBar.vue'
import FilterBar from '../components/layout/FilterBar.vue'

import { useAppShell } from '../composables/useAppShell.js'
import { useSystemState } from '../composables/useSystemState.js'
import { filterNavItemsByAccess, isPlatformAdminUser } from '../utils/accessControl.js'
import { isBusinessDocumentReference } from '../utils/aiDocumentDetailReference.js'
import { loadAiWorkbenchConversationHistory, saveAiWorkbenchConversation } from '../utils/aiWorkbenchConversationStore.js'
import {
  defineAsyncModalView,
  defineAsyncRouteView,
  preloadAppView,
  scheduleRelatedAppViewPreload
} from './scripts/appShellAsyncViews.js'

const employeeSummary = ref(null)
const knowledgeSummary = ref(null)
const documentSummary = ref(null)
const digitalEmployeeSummary = ref(null)
const detailTopBarPayload = ref(null)
const auditDetailOpen = ref(false)
const digitalEmployeeDetailOpen = ref(false)
const receiptFolderDetailOpen = ref(false)
const budgetDetailOpen = ref(false)
const sidebarCollapsed = ref(false)
const sidebarCollapsedBeforeAiMode = ref(false)
const mobileSidebarOpen = ref(false)
const route = useRoute()
const router = useRouter()
const OVERVIEW_DASHBOARDS = new Set(['finance', 'value', 'commercial', 'risk', 'digitalEmployee', 'system'])
const OVERVIEW_RANGES = new Set(['今日', '近10日', '本周', '本月', 'custom'])
const overviewDashboard = ref(resolveOverviewDashboard(route.query.dashboard))
const { companyProfile, currentUser, logout } = useSystemState()

function resolveDefaultWorkbenchMode(user) {
  return isPlatformAdminUser(user) ? 'traditional' : 'ai'
}

function resolveWorkbenchUserKey(user = {}) {
  const roleCodes = Array.isArray(user?.roleCodes) ? user.roleCodes.join(',') : ''
  return [
    user?.id,
    user?.userId,
    user?.username,
    user?.account,
    user?.name,
    user?.role,
    roleCodes,
    user?.isAdmin ? 'admin' : 'user'
  ].map((item) => String(item || '').trim()).join('|')
}

const workbenchMode = ref(resolveDefaultWorkbenchMode(currentUser.value))
const aiSidebarCommandSeq = ref(0)
const aiSidebarCommand = ref({ seq: 0, type: '', payload: null })
const aiActiveConversationId = ref('')
const aiConversationHistory = ref([])
const AuditView = defineAsyncRouteView('audit')
const BudgetCenterView = defineAsyncRouteView('budget')
const DigitalEmployeesView = defineAsyncRouteView('digitalEmployees')
const DocumentsCenterView = defineAsyncRouteView('documents')
const EmployeeManagementView = defineAsyncRouteView('employees')
const OverviewView = defineAsyncRouteView('overview')
const PersonalWorkbenchView = defineAsyncRouteView('workbench')
const PoliciesView = defineAsyncRouteView('policies')
const ReceiptFolderView = defineAsyncRouteView('receiptFolder')
const SettingsView = defineAsyncRouteView('settings')
const TravelReimbursementCreateView = defineAsyncModalView('travelCreate')
const TravelRequestDetailView = defineAsyncRouteView('travelDetail')

function toggleSidebarCollapsed() {
  sidebarCollapsed.value = !sidebarCollapsed.value
}

function handleNavigateWithMobileClose(viewId) {
  void handleNavigate(viewId)
  mobileSidebarOpen.value = false
}

function prefetchAppView(viewId) {
  void preloadAppView(viewId).catch(() => {})
}

function toggleWorkbenchMode() {
  const nextMode = workbenchMode.value === 'ai' ? 'traditional' : 'ai'
  if (nextMode === 'ai') {
    sidebarCollapsedBeforeAiMode.value = sidebarCollapsed.value
    workbenchMode.value = nextMode
    sidebarCollapsed.value = false
    return
  }

  workbenchMode.value = nextMode
  sidebarCollapsed.value = sidebarCollapsedBeforeAiMode.value
}

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

const PRODUCT_DISPLAY_NAME = '易财费控'
const ENTERPRISE_DISPLAY_NAME = '远光软件股份有限公司'
const filteredNavItems = computed(() => filterNavItemsByAccess(navItems, currentUser.value))
const isAiShellMode = computed(() => workbenchMode.value === 'ai')
const isWorkbenchAiMode = computed(() => activeView.value === 'workbench' && workbenchMode.value === 'ai')
const DOCUMENT_DETAIL_RETURN_TARGETS = new Set(['workbench', 'conversation', 'value'])
const DETAIL_TOPBAR_FALLBACKS = {
  audit: {
    title: '规则中心详情',
    desc: '查看规则配置、版本审核、测试结果与上线状态。'
  },
  digitalEmployees: {
    title: '数字员工详情',
    desc: '查看数字员工配置、执行计划、运行记录与源文件。'
  },
  receiptFolder: {
    title: '票据详情',
    desc: '查看票据源文件、OCR 识别信息与关联状态。'
  },
  budget: {
    title: '预算详情',
    desc: '查看预算周期、费用占比、审核信息与预算明细。'
  }
}
const customDetailTopBarActive = computed(() => (
  (activeView.value === 'audit' && auditDetailOpen.value) ||
  (activeView.value === 'digitalEmployees' && digitalEmployeeDetailOpen.value) ||
  (activeView.value === 'receiptFolder' && receiptFolderDetailOpen.value) ||
  (activeView.value === 'budget' && budgetDetailOpen.value)
))
const resolvedTopBarView = computed(() => (
  customDetailTopBarActive.value
    ? detailTopBarPayload.value?.view || DETAIL_TOPBAR_FALLBACKS[activeView.value] || topBarView.value
    : topBarView.value
))
const resolvedDetailMode = computed(() => (
  detailMode.value ||
  customDetailTopBarActive.value
))
const resolvedDetailAlerts = computed(() => (
  customDetailTopBarActive.value
    ? detailTopBarPayload.value?.alerts || []
    : detailAlerts.value
))
const resolvedDetailKpis = computed(() => (
  customDetailTopBarActive.value ? detailTopBarPayload.value?.kpis || [] : []
))

function resolveOverviewDashboard(value) {
  const normalized = Array.isArray(value) ? String(value[0] || '') : String(value || '')
  return OVERVIEW_DASHBOARDS.has(normalized) ? normalized : 'finance'
}

function resolveOverviewRange(value) {
  const normalized = Array.isArray(value) ? String(value[0] || '') : String(value || '')
  return OVERVIEW_RANGES.has(normalized) ? normalized : '近10日'
}

function resolveOverviewDate(value) {
  const normalized = Array.isArray(value) ? String(value[0] || '') : String(value || '')
  return /^\d{4}-\d{2}-\d{2}$/u.test(normalized) ? normalized : ''
}

function overviewQuerySignature(query = {}) {
  return JSON.stringify({
    dashboard: query.dashboard || '',
    range: query.range || '',
    start: query.start || '',
    end: query.end || ''
  })
}

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

function resolveActiveAiConversationSnapshot() {
  const conversationId = String(aiActiveConversationId.value || '').trim()
  if (!conversationId) {
    return null
  }
  const history = aiConversationHistory.value.length
    ? aiConversationHistory.value
    : loadAiWorkbenchConversationHistory(currentUser.value || {})
  return history.find((item) => String(item.id || item.conversationId || '').trim() === conversationId) || null
}

async function handleDocumentDetailBack() {
  const shouldRestoreConversation = detailReturnTarget.value === 'conversation'
  const activeConversation = shouldRestoreConversation ? resolveActiveAiConversationSnapshot() : null
  const navigation = closeRequestDetail()
  if (navigation && typeof navigation.then === 'function') {
    await navigation
  }

  if (!shouldRestoreConversation || !activeConversation) {
    return
  }

  workbenchMode.value = 'ai'
  sidebarCollapsed.value = false
  await nextTick()
  dispatchAiSidebarCommand('open-recent', activeConversation)
}

function openWorkbenchDocument(payload = {}) {
  const payloadClaimId = String(payload.claimId || payload.claim_id || '').trim()
  const payloadId = String(payload.id || '').trim()
  const payloadClaimNo = String(
    payload.claimNo ||
    payload.claim_no ||
    payload.documentNo ||
    payload.document_no ||
    ''
  ).trim()
  const requestId = String(payloadClaimId || payloadId || payloadClaimNo).trim()
  if (!requestId) {
    return
  }

  const requestCandidates = Array.isArray(workbenchRequests.value) && workbenchRequests.value.length
    ? workbenchRequests.value
    : requests.value
  const request = requestCandidates.find((item) => (
    String(item.claimId || '').trim() === requestId
    || String(item.id || '').trim() === requestId
    || String(item.claimNo || '').trim() === requestId
    || String(item.documentNo || '').trim() === requestId
  ))
  const explicitReturnTo = resolveDocumentDetailReturnTarget(payload.returnTo)
  const fallbackToWorkbench = (
    String(payload.source || '').trim() === 'workbench'
    || activeView.value === 'workbench'
  )
  const returnTo = explicitReturnTo || (fallbackToWorkbench ? 'workbench' : '')
  const payloadIdIsBusinessNo = isBusinessDocumentReference(payloadId)
  const fallbackClaimId = payloadClaimId || (payloadClaimNo || payloadIdIsBusinessNo ? '' : payloadId || requestId)
  const fallbackClaimNo = payloadClaimNo || (payloadIdIsBusinessNo ? payloadId : fallbackClaimId ? '' : requestId)
  const detailPayload = request || {
    ...payload,
    id: payloadId || fallbackClaimId || fallbackClaimNo || requestId,
    claimId: fallbackClaimId,
    claimNo: fallbackClaimNo,
    documentNo: String(payload.documentNo || payload.document_no || fallbackClaimNo || requestId).trim(),
    detailLookupOnly: true
  }
  openRequestDetail(detailPayload, { returnTo })
}

function dispatchAiSidebarCommand(type, payload = null) {
  aiSidebarCommandSeq.value += 1
  aiSidebarCommand.value = {
    seq: aiSidebarCommandSeq.value,
    type,
    payload
  }
}

async function openAiConversationWorkspace(type, payload = null) {
  if (activeView.value !== 'workbench') {
    const navigation = handleNavigate('workbench')
    if (navigation && typeof navigation.then === 'function') {
      await navigation
    }
    await nextTick()
  }

  dispatchAiSidebarCommand(type, payload)
}

function openAiSidebarNewChat() {
  aiActiveConversationId.value = ''
  void openAiConversationWorkspace('new-chat')
}

function openAiSidebarRecent(item = {}) {
  aiActiveConversationId.value = String(item.id || '').trim()
  void openAiConversationWorkspace('open-recent', item)
}

function handleAiConversationChange(payload = {}) {
  aiActiveConversationId.value = String(payload.id || '').trim()
}

function handleAiConversationHistoryChange(payload = []) {
  aiConversationHistory.value = Array.isArray(payload) ? payload : []
}

async function handleDetailRequestDeleted(payload = {}) {
  await handleRequestDeleted(payload)
  aiConversationHistory.value = loadAiWorkbenchConversationHistory(currentUser.value || {})
}

function handleAiConversationRename(payload = {}) {
  const conversationId = String(payload.id || '').trim()
  const title = String(payload.title || '').trim()
  if (!conversationId || !title) {
    return
  }

  const target = aiConversationHistory.value.find((item) => String(item.id || '').trim() === conversationId)
  if (!target) {
    return
  }

  aiConversationHistory.value = saveAiWorkbenchConversation(currentUser.value || {}, {
    ...target,
    title
  })

  if (aiActiveConversationId.value === conversationId) {
    dispatchAiSidebarCommand('open-recent', {
      ...target,
      title
    })
  }
}

function handleLogout() {
  logout('manual')
}

watch(
  () => currentUser.value,
  (user, previousUser) => {
    if (resolveWorkbenchUserKey(user) !== resolveWorkbenchUserKey(previousUser)) {
      const nextMode = resolveDefaultWorkbenchMode(user)
      workbenchMode.value = nextMode
      if (nextMode === 'ai') {
        sidebarCollapsed.value = false
      }
    }
    aiConversationHistory.value = loadAiWorkbenchConversationHistory(user || {})
  },
  { immediate: true }
)

watch(
  () => activeView.value,
  (view) => {
    scheduleRelatedAppViewPreload(view)
  },
  { immediate: true }
)

watch(
  () => [activeView.value, overviewQuerySignature(route.query)],
  ([view]) => {
    if (view !== 'overview') return
    overviewDashboard.value = resolveOverviewDashboard(route.query.dashboard)
    activeRange.value = resolveOverviewRange(route.query.range)
    if (activeRange.value === 'custom') {
      const start = resolveOverviewDate(route.query.start)
      const end = resolveOverviewDate(route.query.end)
      if (start && end && start <= end) customRange.value = { start, end }
    }
  },
  { immediate: true }
)

watch(
  () => [
    activeView.value,
    overviewDashboard.value,
    activeRange.value,
    customRange.value?.start,
    customRange.value?.end
  ],
  ([view]) => {
    if (view !== 'overview') return
    const nextQuery = {
      ...route.query,
      dashboard: resolveOverviewDashboard(overviewDashboard.value),
      range: resolveOverviewRange(activeRange.value)
    }
    if (activeRange.value === 'custom' && customRange.value?.start && customRange.value?.end) {
      nextQuery.start = customRange.value.start
      nextQuery.end = customRange.value.end
    } else {
      delete nextQuery.start
      delete nextQuery.end
    }
    if (overviewQuerySignature(nextQuery) !== overviewQuerySignature(route.query)) {
      void router.replace({ query: nextQuery })
    }
  },
  { immediate: true }
)
</script>
