import { defineStore } from 'pinia'
import { reactive } from 'vue'
import { API } from '@/Api'
import type { Message, Role, EventLogEntry, InitialDraft } from '@/types/messages'

interface ConversationState {
  id: string
  messages: Message[]
  agentIds: string[]
  title?: string
  lastUpdated: string
  isStreaming: boolean
  streamingReply: string
  liveEvents: Array<{ kind: string; data: any }>
  detailedEventLog: EventLogEntry[]
  hasPendingLiveEvent: boolean
  isInitializing: boolean
  draftMode?: boolean
  initialDraft?: InitialDraft | null
}

interface ConversationsById {
  [conversationId: string]: ConversationState
}

export const useConversationStore = defineStore('conversation', {
  state: () => ({
    conversations: reactive<ConversationsById>({}),
    activeConversationId: null as string | null,
    loading: false,
  }),

  getters: {
    activeConversation: (state): ConversationState | null => {
      if (!state.activeConversationId) return null
      return state.conversations[state.activeConversationId] || null
    },

    activeMessages: (state): Message[] => {
      const active = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      if (!active) return []

      if (!active.isStreaming || !active.streamingReply) {
        return active.messages
      }

      return [
        ...active.messages,
        {
          role: 'assistant' as Role,
          content: active.streamingReply,
          hasEventLog: false,
        } satisfies Message,
      ]
    },

    isConversationEmpty: (state): boolean => {
      const active = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      return !active || active.messages.length === 0
    },

    hasSelectedAgents: (state): boolean => {
      const active = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      return active ? active.agentIds.length > 0 : false
    },

    showEmptyState: (state): boolean => {
      const active = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      return (
        !active ||
        (!active.isInitializing && active.agentIds.length === 0 && active.messages.length === 0)
      )
    },

    showAgentPromptState: (state): boolean => {
      const active = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      return (
        !active ||
        (!active.isInitializing && active.agentIds.length > 0 && active.messages.length === 0)
      )
    },

    isActiveConversationInitializing: (state): boolean => {
      const conversation = state.activeConversationId
        ? state.conversations[state.activeConversationId]
        : null
      return conversation ? conversation.isInitializing : false
    },

    allConversationIds: (state): string[] => {
      return Object.keys(state.conversations)
    },

    conversationsWithStreaming: (state): string[] => {
      return Object.keys(state.conversations).filter((id) => state.conversations[id].isStreaming)
    },

    conversationTitleById: (state) => {
      return (conversationId: string) => {
        const conversation = state.conversations[conversationId]
        return conversation ? conversation.title || '' : ''
      }
    },
  },

  actions: {
    // Initialize a new conversation
    initializeConversation(
      conversationId: string,
      agentIds: string[] = [],
      options: {
        draftMode?: boolean
        initialDraft?: InitialDraft | null
        skipInitialLoad?: boolean
      } = {}
    ) {
      if (this.conversations[conversationId]) {
        return
      }

      const now = new Date().toISOString()
      this.conversations[conversationId] = {
        id: conversationId,
        messages: [],
        agentIds: [...agentIds],
        lastUpdated: now,
        isStreaming: false,
        streamingReply: '',
        liveEvents: [],
        detailedEventLog: [],
        hasPendingLiveEvent: false,
        isInitializing: true,
        draftMode: options.draftMode || false,
        initialDraft: options.initialDraft || null,
      }
    },

    // Set the active conversation
    setActiveConversation(conversationId: string | null) {
      this.activeConversationId = conversationId
    },

    // Load conversation data from API
    async loadConversation(
      conversationId: string,
      options: {
        draftMode?: boolean
        initialDraft?: InitialDraft | null
        skipInitialLoad?: boolean
        agentIds?: string[]
      } = {}
    ) {
      let conversation = this.conversations[conversationId]
      if (!conversation) {
        this.initializeConversation(conversationId, options.agentIds || [], options)
        conversation = this.conversations[conversationId]
      }

      conversation.isInitializing = true

      try {
        if (options.skipInitialLoad) {
          conversation.isInitializing = false
          return
        }

        if (options.draftMode && options.initialDraft?.id === conversationId) {
          conversation.messages = options.initialDraft.messages
          conversation.agentIds = options.initialDraft.agentIds
          conversation.isInitializing = false
          return
        }

        if (options.draftMode) {
          const { data } = await API.getDraftConversation(options.agentIds?.[0] || '')
          conversation.messages = data?.messages || []
          conversation.agentIds = data?.agentIds || [...(options.agentIds || [])]
        } else {
          const { data } = await API.getConversation(conversationId)
          conversation.messages = data.messages || []
          conversation.agentIds =
            data.agentIds?.length > 0 ? data.agentIds : [...(options.agentIds || [])]
        }
      } catch (err: any) {
        if (!(options.draftMode && err.response?.status === 404)) {
          console.error('Error loading conversation', err)
        }
        conversation.messages = []
      } finally {
        conversation.isInitializing = false
        conversation.lastUpdated = new Date().toISOString()
      }
    },

    // Add a message to the conversation
    addMessage(conversationId: string, message: Message) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.messages.push(message)
      conversation.lastUpdated = new Date().toISOString()
    },

    // Update messages array
    setMessages(conversationId: string, messages: Message[]) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.messages = [...messages]
      conversation.lastUpdated = new Date().toISOString()
    },

    // Update a specific message
    updateMessage(conversationId: string, messageId: string, updates: Partial<Message>) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      const messageIndex = conversation.messages.findIndex((m) => m.id === messageId)
      if (messageIndex !== -1) {
        conversation.messages[messageIndex] = { ...conversation.messages[messageIndex], ...updates }
        conversation.lastUpdated = new Date().toISOString()
      }
    },

    // Truncate messages from a specific point
    truncateMessagesFrom(conversationId: string, messageId: string) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      const messageIndex = conversation.messages.findIndex((m) => m.id === messageId)
      if (messageIndex !== -1) {
        conversation.messages = conversation.messages.slice(0, messageIndex + 1)
        conversation.lastUpdated = new Date().toISOString()
      }
    },

    // Update agent IDs for a conversation
    updateAgentIds(conversationId: string, agentIds: string[]) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.agentIds = [...agentIds]
      conversation.lastUpdated = new Date().toISOString()
    },

    // Update conversation title
    updateTitle(conversationId: string, title: string) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.title = title
      conversation.lastUpdated = new Date().toISOString()
    },

    // Streaming state management
    setStreamingState(conversationId: string, isStreaming: boolean) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.isStreaming = isStreaming
      if (!isStreaming) {
        conversation.streamingReply = ''
        conversation.liveEvents = []
        conversation.detailedEventLog = []
        conversation.hasPendingLiveEvent = false
      }
    },

    setStreamingReply(conversationId: string, reply: string) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.streamingReply = reply
    },

    setLiveEvents(conversationId: string, events: Array<{ kind: string; data: any }> | undefined) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.liveEvents = Array.isArray(events) ? [...events] : []
    },

    setDetailedEventLog(conversationId: string, eventLog: EventLogEntry[] | undefined) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      // Debug logging to help identify issues
      if (!Array.isArray(eventLog) && eventLog !== undefined) {
        console.warn(
          'setDetailedEventLog received non-array value:',
          eventLog,
          'for conversation:',
          conversationId
        )
      }

      conversation.detailedEventLog = Array.isArray(eventLog) ? [...eventLog] : []
    },

    setPendingLiveEvent(conversationId: string, hasPending: boolean) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.hasPendingLiveEvent = hasPending
    },

    // Clear conversation state
    clearConversation(conversationId: string) {
      const conversation = this.conversations[conversationId]
      if (!conversation) return

      conversation.messages = []
      conversation.isStreaming = false
      conversation.streamingReply = ''
      conversation.liveEvents = []
      conversation.detailedEventLog = []
      conversation.hasPendingLiveEvent = false
      conversation.isInitializing = false
      conversation.lastUpdated = new Date().toISOString()
    },

    // Remove conversation from store
    removeConversation(conversationId: string) {
      delete this.conversations[conversationId]
      if (this.activeConversationId === conversationId) {
        this.activeConversationId = null
      }
    },

    // Get conversation by ID
    getConversation(conversationId: string): ConversationState | null {
      return this.conversations[conversationId] || null
    },

    // Check if conversation exists
    hasConversation(conversationId: string): boolean {
      return conversationId in this.conversations
    },

    // Get all conversations
    getAllConversations(): ConversationState[] {
      return Object.values(this.conversations)
    },

    // Cleanup old conversations (optional - for memory management)
    cleanupOldConversations(keepIds: string[] = []) {
      const now = Date.now()
      const oneHour = 60 * 60 * 1000 // 1 hour

      Object.keys(this.conversations).forEach((id) => {
        if (keepIds.includes(id)) return

        const conversation = this.conversations[id]
        const lastUpdated = new Date(conversation.lastUpdated).getTime()

        // Remove conversations older than 1 hour that are not streaming
        if (now - lastUpdated > oneHour && !conversation.isStreaming) {
          delete this.conversations[id]
        }
      })
    },
  },
})
