import { ref, onMounted, onUnmounted, nextTick, computed } from 'vue'
import { usePage } from '@inertiajs/vue3'
import axios from 'axios'

export function usePublicChat() {
    const page = usePage()

    // ========== STATE ==========
    const currentChat = ref(null)
    const openChat = ref(false)
    const unreadCount = ref(0)
    const chatId = ref(null)
    const contactId = ref(null)
    const message = ref('')
    const isTyping = ref(false)
    const typingUser = ref(null)
    const typingTimeout = ref(null)
    const initUser = ref({
        first_name: '',
        last_name: '',
        email: '',
        subject: null,
        department: null,
        priority: null,
        source: null
    })

    // Channel reference for cleanup
    let channelRef = null
    let globalListenerHandler = null
    let scrollTimeout = null
    let messageIds = new Set() // Fast duplicate checking
    
    // Cached container reference
    let messagesContainer = null

    // ========== UTILITY FUNCTIONS ==========
    const getMessagesContainer = () => {
        if (!messagesContainer) {
            messagesContainer = document.querySelector('.chat-messages')
        }
        return messagesContainer
    }

    const scrollToBottom = () => {
        // Debounce scroll operations
        if (scrollTimeout) {
            clearTimeout(scrollTimeout)
        }
        
        scrollTimeout = setTimeout(() => {
            nextTick(() => {
                const container = getMessagesContainer()
                if (container) {
                    container.scrollTop = container.scrollHeight
                }
            })
        }, 50)
    }

    const formatMessage = (msg) => {
        if (!msg) return null
        
        // Return minimal structure for performance
        // Use Object.freeze for immutable data (helps Vue optimize)
        return Object.freeze({
            id: msg.id,
            message: msg.message || '',
            conversation_id: msg.conversation_id,
            user_id: msg.user_id,
            contact_id: msg.contact_id,
            created_at: msg.created_at,
            updated_at: msg.updated_at,
            user: msg.user ? Object.freeze({
                id: msg.user.id,
                first_name: msg.user.first_name,
                last_name: msg.user.last_name,
                name: msg.user.name
            }) : null,
            contact: msg.contact ? Object.freeze({
                id: msg.contact.id,
                first_name: msg.contact.first_name,
                last_name: msg.contact.last_name,
                email: msg.contact.email
            }) : null
        })
    }

    // ========== MESSAGE PROCESSING ==========
    // Limit message history for performance (keep last 500 messages)
    const MAX_MESSAGES = 500
    
    const processIncomingMessage = (event) => {
        if (!event?.chatMessage) {
            return false
        }

        const messageObj = formatMessage(event.chatMessage)

        // Fast validation
        const eventConvId = parseInt(messageObj.conversation_id || 0)
        const currentConvId = parseInt(chatId.value || 0)
        
        if (eventConvId !== currentConvId || !currentChat.value) {
            return false
        }

        // Fast duplicate check using Set
        if (messageIds.has(messageObj.id)) {
            return false
        }

        // Initialize messages array
        if (!currentChat.value.messages) {
            currentChat.value.messages = []
        }

        // Add message
        currentChat.value.messages.push(messageObj)
        messageIds.add(messageObj.id)
        
        // Limit message history to prevent memory issues
        if (currentChat.value.messages.length > MAX_MESSAGES) {
            const removed = currentChat.value.messages.shift()
            if (removed) {
                messageIds.delete(removed.id)
            }
        }
        
        scrollToBottom()
        return true
    }

    // ========== CHANNEL MANAGEMENT ==========
    const setupChannelListener = () => {
        // Clean up existing channel
        if (channelRef) {
            try {
                const oldChannelName = channelRef.name || `chat.${chatId.value}`
                window.Echo.leaveChannel(oldChannelName)
            } catch (error) {
                // Silent fail
            }
            channelRef = null
        }

        // Validate prerequisites
        if (!chatId.value || !window.Echo) {
            return
        }

        const pusher = window.Echo?.connector?.pusher
        if (!pusher) {
            return
        }

        const connectionState = pusher.connection?.state
        if (connectionState !== 'connected' && connectionState !== 'connecting') {
            // Wait for connection (only bind once)
            const connectedHandler = () => {
                pusher.connection.unbind('connected', connectedHandler)
                setTimeout(() => setupChannelListener(), 100)
            }
            pusher.connection.bind('connected', connectedHandler)
            return
        }

        const channelName = `chat.${chatId.value}`

        try {
            // Create channel
            const channel = window.Echo.channel(channelName)
            channelRef = channel

            // Setup subscription handlers and message listener
            const setupListener = () => {
                let listenerSetup = false

                // Subscription success handler
                const onSubscriptionSucceeded = () => {
                    if (!listenerSetup) {
                        listenerSetup = true
                        
                        // Try channel.listen() method
                        try {
                            channel.listen('NewChatMessage', (event) => {
                                processIncomingMessage(event)
                            })
                        } catch (error) {
                            // Silent fail, fallback to global listener
                        }
                    }
                }

                // Subscription error handler
                const onSubscriptionError = (error) => {
                    // Silent fail - errors are handled gracefully
                }

                // Attach subscription handlers
                if (channel.subscription) {
                    channel.subscription.bind('pusher:subscription_succeeded', onSubscriptionSucceeded)
                    channel.subscription.bind('pusher:subscription_error', onSubscriptionError)
                    
                    // If already subscribed, setup listener immediately
                    if (channel.subscription.subscribed) {
                        onSubscriptionSucceeded()
                    }
                } else {
                    // Wait for subscription object to be available
                    const checkSubscription = (attempts = 10) => {
                        if (channel.subscription) {
                            channel.subscription.bind('pusher:subscription_succeeded', onSubscriptionSucceeded)
                            channel.subscription.bind('pusher:subscription_error', onSubscriptionError)
                            
                            if (channel.subscription.subscribed) {
                                onSubscriptionSucceeded()
                            }
                        } else if (attempts > 0) {
                            setTimeout(() => checkSubscription(attempts - 1), 100)
                        }
                    }
                    checkSubscription()
                }
            }

            // Setup listener
            setupListener()

            // Global listener as fallback (only set up once)
            if (pusher.bind_global && !globalListenerHandler) {
                globalListenerHandler = (eventName, data) => {
                    // Early exit for non-relevant events
                    if (eventName !== 'NewChatMessage') {
                        return
                    }
                    
                    // Fast path: check conversation ID before processing
                    let conversationId = null
                    if (data?.chatMessage?.conversation_id) {
                        conversationId = parseInt(data.chatMessage.conversation_id)
                    } else if (data?.conversation_id) {
                        conversationId = parseInt(data.conversation_id)
                    }
                    
                    // Early exit if not for current conversation
                    if (!conversationId || conversationId !== parseInt(chatId.value || 0)) {
                        return
                    }
                    
                    // Extract chatMessage from data
                    let chatMessage = null
                    if (data?.chatMessage) {
                        chatMessage = data.chatMessage
                    } else if (data?.id && data?.conversation_id) {
                        chatMessage = data
                    }

                    if (chatMessage && currentChat.value) {
                        processIncomingMessage({ chatMessage })
                    }
                }
                
                pusher.bind_global(globalListenerHandler)
            }

        } catch (error) {
            // Silent fail - errors are handled gracefully
        }
    }

    const cleanupChannel = () => {
        if (channelRef && chatId.value) {
            try {
                const channelName = `chat.${chatId.value}`
                window.Echo.leaveChannel(channelName)
            } catch (error) {
                // Silent fail
            }
            channelRef = null
        }
        
        // Clean up global listener
        if (globalListenerHandler && window.Echo?.connector?.pusher?.unbind_global) {
            try {
                window.Echo.connector.pusher.unbind_global(globalListenerHandler)
                globalListenerHandler = null
            } catch (error) {
                // Silent fail
            }
        }
    }

    // ========== CHAT OPERATIONS ==========
    const toggleChat = () => {
        openChat.value = !openChat.value
    }

    const startChat = async () => {
        if (!initUser.value.email || !initUser.value.first_name || !initUser.value.last_name) {
            alert('Please fill in all required fields')
            return
        }

        const chatData = {
            first_name: initUser.value.first_name,
            last_name: initUser.value.last_name,
            email: initUser.value.email,
            subject: initUser.value.subject || null,
            department: initUser.value.department || null,
            priority: initUser.value.priority || null,
            source: initUser.value.source || null
        }

        try {
            const response = await axios.post(route('chat.init'), chatData)

            if (response.data?.success && response.data.conversation) {
                const conversation = response.data.conversation

                // Set chat data
                currentChat.value = conversation
                chatId.value = conversation.id
                contactId.value = conversation.contact_id

                // Initialize messages and message IDs set
                if (!conversation.messages) {
                    conversation.messages = []
                    messageIds.clear()
                } else {
                    // Limit initial message load for performance
                    const allMessages = conversation.messages.map(formatMessage)
                    conversation.messages = allMessages.slice(-MAX_MESSAGES)
                    // Populate message IDs set for fast duplicate checking
                    messageIds = new Set(conversation.messages.map(m => m.id))
                }

                // Store in localStorage
                localStorage.setItem('chat_id', chatId.value)
                localStorage.setItem('contact_id', contactId.value)

                // Open chat
                openChat.value = true

                // Scroll to bottom
                scrollToBottom()

                // Setup channel listener with retry
                const setupWithRetry = (retries = 3) => {
                    setTimeout(() => {
                        if (!window.Echo) {
                            if (retries > 0) {
                                setupWithRetry(retries - 1)
                            }
                            return
                        }
                        setupChannelListener()
                    }, 500)
                }
                setupWithRetry()

            } else {
                throw new Error(response.data?.message || 'Failed to start chat')
            }
        } catch (error) {
            const message = error.response?.data?.message || 
                           error.message || 
                           'Failed to start chat. Please try again.'
            alert(message)
        }
    }

    const handleStartChat = (userData) => {
        initUser.value = { ...initUser.value, ...userData }
        startChat()
    }

    const handleSendMessage = async (messageData) => {
        if (!messageData?.message?.trim()) {
            return
        }

        if (!currentChat.value || !currentChat.value.id) {
            alert('Please start a chat first')
            return
        }

        const payload = {
            message: messageData.message.trim(),
            contact_id: currentChat.value.contact_id,
            conversation_id: currentChat.value.id
        }

        try {
            const response = await axios.post(route('chat.send_message'), payload)

            if (response.data?.success) {
                // Add message immediately if provided
                if (response.data.message) {
                    const newMessage = formatMessage(response.data.message)
                    
                    if (!currentChat.value.messages) {
                        currentChat.value.messages = []
                    }

                    // Check for duplicates using Set
                    if (!messageIds.has(newMessage.id)) {
                        currentChat.value.messages.push(newMessage)
                        messageIds.add(newMessage.id)
                    }
                }

                scrollToBottom()
            } else {
                throw new Error(response.data?.message || 'Failed to send message')
            }
        } catch (error) {
            const message = error.response?.data?.message || 
                           error.message || 
                           'Failed to send message. Please try again.'
            alert(message)
        }
    }

    const loadExistingChat = async () => {
        const savedChatId = localStorage.getItem('chat_id')
        const savedContactId = localStorage.getItem('contact_id')

        if (!savedChatId || !savedContactId) {
            return
        }

        try {
            const response = await axios.get(route('chat.conversation', [savedChatId, savedContactId]))

            if (response.data?.success && response.data.conversation) {
                const conversation = response.data.conversation

                // Set chat data
                currentChat.value = conversation
                chatId.value = parseInt(savedChatId)
                contactId.value = parseInt(savedContactId)

                // Initialize messages and message IDs set
                if (!conversation.messages) {
                    conversation.messages = []
                    messageIds.clear()
                } else {
                    // Limit initial message load for performance
                    const allMessages = conversation.messages.map(formatMessage)
                    conversation.messages = allMessages.slice(-MAX_MESSAGES)
                    messageIds = new Set(conversation.messages.map(m => m.id))
                }

                // Open chat
                openChat.value = true

                // Scroll to bottom
                scrollToBottom()

                // Setup channel listener with retry
                const setupWithRetry = (retries = 3) => {
                    setTimeout(() => {
                        if (!window.Echo) {
                            if (retries > 0) {
                                setupWithRetry(retries - 1)
                            }
                            return
                        }
                        setupChannelListener()
                    }, 500)
                }
                setupWithRetry()

            } else {
                // Clear invalid data
                localStorage.removeItem('chat_id')
                localStorage.removeItem('contact_id')
            }
        } catch (error) {
            // Clear invalid data
            localStorage.removeItem('chat_id')
            localStorage.removeItem('contact_id')
        }
    }

    const clearChat = () => {
        cleanupChannel()
        currentChat.value = null
        openChat.value = false
        chatId.value = null
        contactId.value = null
        message.value = ''
        isTyping.value = false
        typingUser.value = null
        messageIds.clear()
        messagesContainer = null
        localStorage.removeItem('chat_id')
        localStorage.removeItem('contact_id')
    }

    // ========== LIFECYCLE ==========
    onMounted(() => {
        loadExistingChat()
    })

    onUnmounted(() => {
        cleanupChannel()
        if (typingTimeout.value) {
            clearTimeout(typingTimeout.value)
        }
        if (scrollTimeout) {
            clearTimeout(scrollTimeout)
        }
        messageIds.clear()
        messagesContainer = null
    })

    // ========== RETURN ==========
    return {
        // State
        currentChat,
        openChat,
        unreadCount,
        chatId,
        contactId,
        message,
        isTyping,
        typingUser,
        initUser,

        // Methods
        toggleChat,
        startChat,
        handleStartChat,
        handleSendMessage,
        loadExistingChat,
        clearChat,
        setupChannelListener,
        refreshChannel: setupChannelListener
    }
}
