import { nextTick, ref } from 'vue'

import { fetchLatestConversation } from '../../services/orchestrator.js'
import {
  clearAssistantSessionSnapshot,
  readAssistantSessionSnapshot,
  writeAssistantSessionSnapshot
} from '../../utils/assistantSessionSnapshot.js'
import {
  buildReviewFilePreviewsFromMessages,
  filterPersistableFilePreviews
} from './travelReimbursementAttachmentModel.js'
import {
  ASSISTANT_SESSION_TYPES,
  filterAssistantSessionTypes,
  SESSION_TYPE_APPLICATION,
  SESSION_TYPE_BUDGET,
  SESSION_TYPE_EXPENSE,
  SESSION_TYPE_STEWARD,
  buildInitialInsightFromConversation,
  buildWelcomeInsight,
  buildWelcomeQuickActions,
  createWelcomeAssistantMessage,
  hasMeaningfulSessionMessages,
  normalizeInitialConversationMessages,
  normalizeSnapshotMessages,
  normalizeAssistantSessionType,
  resolveInitialConversationId,
  resolveInitialDraftClaimId,
  resolveInitialSessionType,
  serializeSessionMessages,
  shouldPreferPersistedSessionState
} from './travelReimbursementConversationModel.js'
import {
  createEmptyGuidedFlowState,
  normalizeGuidedFlowState
} from './travelReimbursementGuidedFlowModel.js'

const STEWARD_IDLE_INSIGHT = {
  intent: 'idle',
  metricLabel: '',
  metricValue: '',
  title: '',
  summary: '',
  agent: null
}

export function useTravelReimbursementSessionState({
  props,
  currentUser,
  linkedRequest,
  toast,
  composerDraft,
  adjustComposerTextareaHeight,
  scrollToBottom,
  getSessionRuntimeRefs = () => ({})
}) {
  function resolveAccessibleSessionTypes() {
    return filterAssistantSessionTypes(ASSISTANT_SESSION_TYPES, currentUser.value)
  }

  function resolveAccessibleSessionType(rawSessionType, fallback = resolveDefaultSessionTypeFromEntry()) {
    const normalized = normalizeAssistantSessionType(rawSessionType, fallback)
    const accessible = resolveAccessibleSessionTypes()
    if (accessible.includes(normalized)) {
      return normalized
    }

    const fallbackNormalized = String(fallback || '').trim()
    if (accessible.includes(fallbackNormalized)) {
      return fallbackNormalized
    }

    return accessible[0] || SESSION_TYPE_APPLICATION
  }

  function resolveDefaultSessionTypeFromEntry() {
    const initialSessionType = String(props.initialSessionType || '').trim()
    if (initialSessionType) {
      return initialSessionType
    }
    if (props.entrySource === 'budget') {
      return SESSION_TYPE_BUDGET
    }
    return props.entrySource === 'application' ? SESSION_TYPE_APPLICATION : SESSION_TYPE_EXPENSE
  }

  function refreshWelcomeQuickActions(messages, sessionType) {
    if (!Array.isArray(messages) || !messages.length) {
      return []
    }
    if (isStewardSessionType(sessionType)) {
      return messages.filter((message) => !message?.isWelcome)
    }
    const currentActions = buildWelcomeQuickActions(
      sessionType,
      currentUser.value,
      props.entrySource,
      linkedRequest.value
    )
    return messages.map((message) => (
      message?.isWelcome
        ? { ...message, welcomeQuickActions: currentActions }
        : message
    ))
  }

  function isStewardSessionType(sessionType) {
    return normalizeAssistantSessionType(sessionType) === SESSION_TYPE_STEWARD
  }

  function buildSessionMessages(restoredMessages, sessionType) {
    if (Array.isArray(restoredMessages) && restoredMessages.length) {
      return restoredMessages
    }
    if (isStewardSessionType(sessionType)) {
      return []
    }
    return [createWelcomeAssistantMessage(props.entrySource, linkedRequest.value, sessionType, currentUser.value)]
  }

  function buildSessionInsight(sessionType) {
    if (isStewardSessionType(sessionType)) {
      return { ...STEWARD_IDLE_INSIGHT }
    }
    return buildWelcomeInsight(props.entrySource, linkedRequest.value, sessionType, currentUser.value)
  }

  function normalizeStewardState(value) {
    return value && typeof value === 'object' && !Array.isArray(value) ? value : null
  }

  function buildConversationSessionState(conversation, fallbackSessionType = resolveDefaultSessionTypeFromEntry()) {
    const sessionType = resolveAccessibleSessionType(
      resolveInitialSessionType(conversation, fallbackSessionType),
      fallbackSessionType
    )
    const restoredMessages = refreshWelcomeQuickActions(normalizeInitialConversationMessages(conversation), sessionType)
    const initialInsight = buildInitialInsightFromConversation(conversation)
    const restoredReviewFilePreviews = buildReviewFilePreviewsFromMessages(restoredMessages)

    return {
      sessionType,
      messages: buildSessionMessages(restoredMessages, sessionType),
      conversationId: resolveInitialConversationId(conversation),
      stewardState: normalizeStewardState(conversation?.state_json?.steward_state || conversation?.stateJson?.stewardState),
      draftClaimId: resolveInitialDraftClaimId(conversation),
      currentInsight: isStewardSessionType(sessionType)
        ? buildSessionInsight(sessionType)
        : initialInsight || buildSessionInsight(sessionType),
      reviewFilePreviews: restoredReviewFilePreviews,
      composerDraft: '',
      attachedFiles: [],
      composerFilesExpanded: false,
      composerUploadIntent: '',
      guidedFlowState: createEmptyGuidedFlowState(),
      insightPanelCollapsed: false
    }
  }

  function buildEmptySessionState(sessionType) {
    const normalizedSessionType = resolveAccessibleSessionType(
      sessionType,
      resolveDefaultSessionTypeFromEntry()
    )
    return {
      sessionType: normalizedSessionType,
      messages: buildSessionMessages([], normalizedSessionType),
      conversationId: '',
      stewardState: null,
      draftClaimId: '',
      currentInsight: buildSessionInsight(normalizedSessionType),
      reviewFilePreviews: [],
      composerDraft: '',
      attachedFiles: [],
      composerFilesExpanded: false,
      composerUploadIntent: '',
      guidedFlowState: createEmptyGuidedFlowState(),
      insightPanelCollapsed: false
    }
  }

  function buildPersistedSessionState(snapshot, fallbackSessionType = resolveDefaultSessionTypeFromEntry()) {
    const state = snapshot?.state && typeof snapshot.state === 'object' ? snapshot.state : null
    if (!state) {
      return null
    }

    const sessionType = resolveAccessibleSessionType(
      state.sessionType || snapshot.sessionType || fallbackSessionType,
      fallbackSessionType
    )
    const restoredMessages = refreshWelcomeQuickActions(normalizeSnapshotMessages(state.messages), sessionType)
    if (
      !hasMeaningfulSessionMessages(restoredMessages)
        && !String(state.conversationId || '').trim()
        && !String(state.draftClaimId || '').trim()
    ) {
      return null
    }

    return {
      sessionType,
      messages: buildSessionMessages(restoredMessages, sessionType),
      conversationId: String(state.conversationId || '').trim(),
      stewardState: normalizeStewardState(state.stewardState),
      draftClaimId: String(state.draftClaimId || '').trim(),
      currentInsight: isStewardSessionType(sessionType)
        ? buildSessionInsight(sessionType)
        : state.currentInsight || buildSessionInsight(sessionType),
      reviewFilePreviews: filterPersistableFilePreviews(state.reviewFilePreviews),
      composerDraft: String(state.composerDraft || ''),
      attachedFiles: [],
      composerFilesExpanded: false,
      composerUploadIntent: String(state.composerUploadIntent || '').trim(),
      guidedFlowState: normalizeGuidedFlowState(state.guidedFlowState),
      insightPanelCollapsed: Boolean(state.insightPanelCollapsed)
    }
  }

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

  const defaultInitialSessionType = resolveDefaultSessionTypeFromEntry()
  const initialSessionType = resolveAccessibleSessionType(
    props.initialConversation
      ? resolveInitialSessionType(props.initialConversation, defaultInitialSessionType)
      : defaultInitialSessionType,
    defaultInitialSessionType
  )
  const shouldPersistLocalSnapshot = props.entrySource !== 'detail'
  const conversationInitialState = props.initialConversation
    ? buildConversationSessionState(props.initialConversation, initialSessionType)
    : buildEmptySessionState(initialSessionType)
  const canRestorePersistedInitialState =
    shouldPersistLocalSnapshot
      && props.entrySource !== 'budget'
      && !String(props.initialPrompt || '').trim()
      && !props.initialApplicationPreview
      && !props.initialFiles.length
  const persistedInitialSnapshot = readAssistantSessionSnapshot(resolveCurrentUserId(), initialSessionType)
  const persistedInitialState = canRestorePersistedInitialState
    ? buildPersistedSessionState(persistedInitialSnapshot, initialSessionType)
    : null
  const initialSessionState = canRestorePersistedInitialState && shouldPreferPersistedSessionState(
    persistedInitialState,
    persistedInitialSnapshot,
    props.initialConversation
  )
    ? persistedInitialState
    : conversationInitialState

  const activeSessionType = ref(initialSessionState.sessionType)
  const messages = ref(initialSessionState.messages)
  const conversationId = ref(initialSessionState.conversationId)
  const stewardState = ref(normalizeStewardState(initialSessionState.stewardState))
  const draftClaimId = ref(initialSessionState.draftClaimId)
  const reviewFilePreviews = ref(initialSessionState.reviewFilePreviews)
  const sessionSnapshots = ref(
    resolveAccessibleSessionTypes().reduce((result, sessionType) => {
      result[sessionType] = null
      return result
    }, {})
  )
  const currentInsight = ref(initialSessionState.currentInsight)
  const composerUploadIntent = ref(String(initialSessionState.composerUploadIntent || '').trim())
  const guidedFlowState = ref(normalizeGuidedFlowState(initialSessionState.guidedFlowState))
  const insightPanelCollapsed = ref(false)
  const sessionSwitchBusy = ref(false)

  function buildPersistableSessionState(sessionState) {
    const state = sessionState || captureCurrentSessionState()
    return {
      sessionType: resolveAccessibleSessionType(state.sessionType, resolveDefaultSessionTypeFromEntry()),
      messages: serializeSessionMessages(state.messages),
      conversationId: String(state.conversationId || '').trim(),
      stewardState: normalizeStewardState(state.stewardState),
      draftClaimId: String(state.draftClaimId || '').trim(),
      currentInsight: state.currentInsight || null,
      reviewFilePreviews: filterPersistableFilePreviews(state.reviewFilePreviews),
      composerDraft: String(state.composerDraft || ''),
      composerUploadIntent: String(state.composerUploadIntent || '').trim(),
      guidedFlowState: normalizeGuidedFlowState(state.guidedFlowState),
      insightPanelCollapsed: Boolean(state.insightPanelCollapsed)
    }
  }

  function persistSessionState(sessionState = null) {
    if (!shouldPersistLocalSnapshot) {
      return
    }

    const state = sessionState || captureCurrentSessionState()
    const persistedState = buildPersistableSessionState(state)
    const meaningful = Boolean(
      String(persistedState.conversationId || '').trim()
        || String(persistedState.draftClaimId || '').trim()
        || hasMeaningfulSessionMessages(persistedState.messages)
        || Boolean(persistedState.stewardState)
        || String(persistedState.composerDraft || '').trim()
    )

    if (!meaningful) {
      clearAssistantSessionSnapshot(resolveCurrentUserId(), persistedState.sessionType)
      return
    }

    writeAssistantSessionSnapshot(resolveCurrentUserId(), persistedState.sessionType, persistedState)
  }

  function captureCurrentSessionState() {
    const runtimeRefs = getSessionRuntimeRefs()
    return {
      sessionType: activeSessionType.value,
      messages: messages.value,
      conversationId: conversationId.value,
      stewardState: stewardState.value,
      draftClaimId: draftClaimId.value,
      currentInsight: currentInsight.value,
      reviewFilePreviews: reviewFilePreviews.value,
      composerDraft: composerDraft.value,
      attachedFiles: runtimeRefs.attachedFiles?.value ?? [],
      composerFilesExpanded: runtimeRefs.composerFilesExpanded?.value ?? false,
      composerUploadIntent: composerUploadIntent.value,
      guidedFlowState: runtimeRefs.guidedFlowState?.value ?? guidedFlowState.value,
      insightPanelCollapsed: insightPanelCollapsed.value
    }
  }

  function applySessionState(sessionState) {
    const runtimeRefs = getSessionRuntimeRefs()
    const nextState = sessionState || buildEmptySessionState(activeSessionType.value)
    activeSessionType.value = resolveAccessibleSessionType(
      nextState.sessionType,
      resolveDefaultSessionTypeFromEntry()
    )
    messages.value = buildSessionMessages(
      refreshWelcomeQuickActions(nextState.messages, activeSessionType.value),
      activeSessionType.value
    )
    conversationId.value = String(nextState.conversationId || '').trim()
    stewardState.value = normalizeStewardState(nextState.stewardState)
    draftClaimId.value = String(nextState.draftClaimId || '').trim()
    currentInsight.value = isStewardSessionType(activeSessionType.value)
      ? buildSessionInsight(activeSessionType.value)
      : nextState.currentInsight || buildSessionInsight(activeSessionType.value)
    reviewFilePreviews.value = Array.isArray(nextState.reviewFilePreviews) ? nextState.reviewFilePreviews : []
    composerDraft.value = String(nextState.composerDraft || '')
    if (runtimeRefs.attachedFiles) {
      runtimeRefs.attachedFiles.value = Array.isArray(nextState.attachedFiles) ? nextState.attachedFiles : []
    }
    if (runtimeRefs.composerFilesExpanded) {
      runtimeRefs.composerFilesExpanded.value = Boolean(nextState.composerFilesExpanded)
    }
    composerUploadIntent.value = String(nextState.composerUploadIntent || '').trim()
    const nextGuidedFlowState = normalizeGuidedFlowState(nextState.guidedFlowState)
    guidedFlowState.value = nextGuidedFlowState
    if (runtimeRefs.guidedFlowState) {
      runtimeRefs.guidedFlowState.value = nextGuidedFlowState
    }
    insightPanelCollapsed.value = Boolean(nextState.insightPanelCollapsed)
    nextTick(() => {
      adjustComposerTextareaHeight()
      scrollToBottom()
    })
  }

  async function loadLatestSessionState(targetSessionType) {
    const normalizedTarget = resolveAccessibleSessionType(targetSessionType, resolveDefaultSessionTypeFromEntry())
    const payload = await fetchLatestConversation(resolveCurrentUserId(), normalizedTarget, {
      preferRecoverable: normalizedTarget === SESSION_TYPE_EXPENSE
    })
    if (payload?.found && payload.conversation) {
      return buildConversationSessionState(payload.conversation, normalizedTarget)
    }
    return buildEmptySessionState(normalizedTarget)
  }

  async function switchSessionType(targetSessionType) {
    const normalizedTarget = resolveAccessibleSessionType(targetSessionType, resolveDefaultSessionTypeFromEntry())
    if (normalizedTarget === activeSessionType.value || sessionSwitchBusy.value) {
      return
    }

    sessionSnapshots.value[activeSessionType.value] = captureCurrentSessionState()
    if (sessionSnapshots.value[normalizedTarget]) {
      applySessionState(sessionSnapshots.value[normalizedTarget])
      return
    }

    sessionSwitchBusy.value = true
    try {
      const nextState = await loadLatestSessionState(normalizedTarget)
      sessionSnapshots.value[normalizedTarget] = nextState
      applySessionState(nextState)
    } catch (error) {
      const emptyState = buildEmptySessionState(normalizedTarget)
      sessionSnapshots.value[normalizedTarget] = emptyState
      applySessionState(emptyState)
      toast(error?.message || '切换助手失败，请稍后重试。')
    } finally {
      sessionSwitchBusy.value = false
    }
  }

  sessionSnapshots.value[initialSessionState.sessionType] = captureCurrentSessionState()

  return {
    activeSessionType,
    messages,
    conversationId,
    stewardState,
    draftClaimId,
    sessionSnapshots,
    currentInsight,
    reviewFilePreviews,
    composerUploadIntent,
    guidedFlowState,
    insightPanelCollapsed,
    sessionSwitchBusy,
    initialSessionState,
    buildConversationSessionState,
    buildEmptySessionState,
    buildPersistedSessionState,
    resolveCurrentUserId,
    buildPersistableSessionState,
    persistSessionState,
    captureCurrentSessionState,
    applySessionState,
    loadLatestSessionState,
    switchSessionType
  }
}
