import { ref, onMounted, watch } from 'vue'
import { useSocket } from '@/composables/useSocket'
import { useStreamingStore } from '@/store/streamingStore'
import { useConversationStore } from '@/store/conversationStore'
import { useConversationCatalogStore } from '@/store/conversationCatalogStore'
import { usePrefStore } from '@/store/prefStore'
import { useAgents } from '@/composables/useAgents'
import { toast } from 'vue-sonner'
import type { Message, MessageAttachment } from '@/types/messages'

export function useConversationStreaming() {
  const socket = useSocket()
  const streamingStore = useStreamingStore()
  const conversationStore = useConversationStore()
  const catalog = useConversationCatalogStore()
  const { agents: allAgents } = useAgents()

  const isConnected = ref(false)

  // Initialize connection status immediately
  if (socket.value) {
    isConnected.value = socket.value.connected
  }

  // Watch for socket connection status only
  watch(
    socket,
    (newSocket) => {
      isConnected.value = !!newSocket?.connected
    },
    { immediate: true }
  )

  // Send a message
  function sendMessage(
    conversationId: string,
    userMessage: string,
    agentIds: string[] = [],
    draftMode: boolean = false,
    attachments: MessageAttachment[] = [],
    options: { skipLocalAdd?: boolean } = {}
  ) {
    const { skipLocalAdd = false } = options

    if (!socket.value?.connected) {
      toast.error('Connection lost. Please refresh the page.')
      return
    }

    const conversation = conversationStore.getConversation(conversationId)
    if (!conversation) {
      console.error('Conversation not found:', conversationId)
      return
    }

    if (!skipLocalAdd) {
      // Add user message to conversation with attachments
      const userMsg: Message = {
        role: 'user',
        content: userMessage,
        attachments: attachments.length > 0 ? attachments : undefined,
      }
      conversationStore.addMessage(conversationId, userMsg)
    }

    // Update has_attachments if sending with attachments
    if (attachments.length > 0) {
      conversationStore.updateHasAttachments(conversationId, true)
    }

    // Store user message in streaming store for persistence
    streamingStore.setUserMessage(conversationId, userMessage)

    // Set streaming state
    conversationStore.setStreamingState(conversationId, true)
    conversationStore.setLiveEvents(conversationId, [])
    conversationStore.setDetailedEventLog(conversationId, [])
    conversationStore.setPendingLiveEvent(conversationId, false)

    // If this is the first message, add to catalog
    if (!skipLocalAdd && conversation.messages.length === 1 && !draftMode) {
      catalog.addNewConversation(conversationId, agentIds)
    }

    const modeAgentsOff =
      (usePrefStore().uiConf?.allow_chat_to_llm && !conversation.modeAgents) ||
      conversation.has_attachments
    // Send via socket
    const agentsToUse =
      agentIds.length > 0
        ? agentIds
        : allAgents.value
            .filter((a) => a.status === 'active' || a.isEnterprise === true)
            .map((a) => a.id)
    // console.log('Sending message with agents:', modeAgentsOff? [] : agentsToUse, conversation.modeAgents, conversation.selectedLLM, !conversation.modeAgents ? conversation.selectedLLM ?? usePrefStore().uiConf?.default_llm: conversation.selectedLLM)
    // console.log('Pref store base LLM id:', usePrefStore().baseLlmid)
    // console.log('Draft mode:', usePrefStore().uiConf?.default_llm)
    socket.value.emit('stream_message', {
      agentIds: modeAgentsOff ? [] : agentsToUse,
      conversationId: conversationId,
      userMessage: userMessage,
      attachments: attachments,
      draftMode: draftMode,
      modeAgents: conversation.modeAgents,
      selectedLLM: !conversation.modeAgents
        ? conversation.selectedLLM ?? usePrefStore().uiConf!.default_llm
        : conversation.selectedLLM,
    })
  }

  // Cancel streaming
  function cancelStream(conversationId: string) {
    if (!socket.value?.connected) return

    const conversation = conversationStore.getConversation(conversationId)
    if (!conversation) return

    const buffer = streamingStore.getReplyBuffer(conversationId)
    const partial = buffer?.text || conversation.streamingReply

    if (partial) {
      const assistantMsg: Message = {
        role: 'assistant',
        content: partial,
        hasEventLog: false,
      }
      conversationStore.addMessage(conversationId, assistantMsg)
    }

    socket.value.emit('cancel_stream', { conversationId })

    // Clear buffers and reset state
    streamingStore.deleteReplyBuffer(conversationId)
    streamingStore.deleteEventBuffer(conversationId)
    conversationStore.setStreamingState(conversationId, false)
  }

  // Switch to a conversation and restore streaming state if needed
  async function switchToConversation(conversationId: string) {
    if (conversationId === conversationStore.activeConversationId) return

    // Clean up old buffers
    streamingStore.cleanupOldBuffers(conversationId)

    // Set as active
    conversationStore.setActiveConversation(conversationId)

    // Check if there's an active stream for this conversation
    const buffer = streamingStore.getReplyBuffer(conversationId)
    const eventBuffer = streamingStore.getEventBuffer(conversationId)

    if (buffer && !buffer.done) {
      // Stream is still active
      conversationStore.setStreamingReply(conversationId, buffer.text)
      conversationStore.setStreamingState(conversationId, true)

      // Restore user message if needed
      if (buffer.userMessage) {
        const conversation = conversationStore.getConversation(conversationId)
        if (
          conversation &&
          !conversation.messages.some((msg) => msg.content === buffer.userMessage)
        ) {
          const userMsg: Message = { role: 'user', content: buffer.userMessage }
          conversationStore.addMessage(conversationId, userMsg)
        }
      }

      // Restore events
      if (eventBuffer) {
        conversationStore.setLiveEvents(conversationId, eventBuffer.liveEvents)
        conversationStore.setDetailedEventLog(conversationId, eventBuffer.detailedEventLog)
        conversationStore.setPendingLiveEvent(conversationId, eventBuffer.hasPendingLiveEvent)
      }
    } else if (eventBuffer && eventBuffer.liveEvents.length > 0) {
      // Stream finished but we have events to show
      conversationStore.setStreamingState(conversationId, true)
      conversationStore.setLiveEvents(conversationId, eventBuffer.liveEvents)
      conversationStore.setDetailedEventLog(conversationId, eventBuffer.detailedEventLog)
      conversationStore.setPendingLiveEvent(conversationId, eventBuffer.hasPendingLiveEvent)
    } else {
      // Stream finished
      conversationStore.setStreamingState(conversationId, false)
    }
  }

  // Initialize
  onMounted(() => {
    isConnected.value = !!socket.value?.connected
  })

  return {
    isConnected,
    sendMessage,
    cancelStream,
    switchToConversation,
  }
}
