package com.crm.chat.ui.chat

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.crm.chat.data.api.ApiClient
import com.crm.chat.data.model.Chat
import com.crm.chat.data.model.ChatMessage
import com.crm.chat.data.model.SendMessageRequest
import com.crm.chat.data.repository.ChatRepository
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class ChatViewModel : ViewModel() {

    private val _chatState = MutableLiveData<ChatState>()
    val chatState: LiveData<ChatState> = _chatState

    private val _messagesState = MutableLiveData<MessagesState>()
    val messagesState: LiveData<MessagesState> = _messagesState

    private val _sendMessageState = MutableLiveData<SendMessageState>()
    val sendMessageState: LiveData<SendMessageState> = _sendMessageState

    private val _editMessageState = MutableLiveData<EditMessageState>()
    val editMessageState: LiveData<EditMessageState> = _editMessageState

    private val _deleteMessageState = MutableLiveData<DeleteMessageState>()
    val deleteMessageState: LiveData<DeleteMessageState> = _deleteMessageState

    private val _reactionState = MutableLiveData<ReactionState>()
    val reactionState: LiveData<ReactionState> = _reactionState

    private lateinit var chatRepository: ChatRepository

    // Allowed emoji reactions
    companion object {
        val ALLOWED_EMOJIS = listOf("👍", "👎", "❤️", "🔥", "👏", "😀", "🥰", "🤣")
    }
    private var chatId: Long = -1
    private var pollingJob: Job? = null
    private var isChatActive: Boolean = false
    private var previousMessages: List<ChatMessage> = emptyList()

    fun initialize(serverUrl: String, token: String, apiKey: String, chatId: Long) {
        this.chatId = chatId
        val apiClient = ApiClient(serverUrl, apiKey, token)
        chatRepository = ChatRepository(apiClient)

        loadChat()
        loadMessages()
        startPolling()
    }

    private fun loadChat() {
        viewModelScope.launch {
            val result = chatRepository.getChat(chatId)
            result.fold(
                onSuccess = { chat ->
                    // Only update UI if chat information has changed
                    val currentChat = (chatState.value as? ChatState.Success)?.chat
                    if (currentChat == null || hasChatChanged(currentChat, chat)) {
                        _chatState.value = ChatState.Success(chat)
                    }
                    // If no changes, don't update the UI
                },
                onFailure = { exception ->
                    // Only update to error state if we're not already in error state
                    if (chatState.value !is ChatState.Error) {
                        _chatState.value = ChatState.Error(exception.message ?: "Failed to load chat")
                    }
                }
            )
        }
    }

    private fun loadMessages() {
        viewModelScope.launch {
            val result = chatRepository.getChatMessages(chatId)
            result.fold(
                onSuccess = { messagesResponse ->
                    // Sort messages by createdAt in ascending order (oldest first)
                    val sortedMessages = messagesResponse.messages.sortedBy { it.createdAt }

                    // Check if this is the initial load (no previous success state)
                    val isInitialLoad = messagesState.value !is MessagesState.Success
                    val currentMessages = (messagesState.value as? MessagesState.Success)?.messages ?: emptyList()

                    if (isInitialLoad || hasMessagesChanged(currentMessages, sortedMessages)) {
                        println("DEBUG: Messages changed or initial load, updating UI (${sortedMessages.size} messages)")

                        previousMessages = sortedMessages
                        _messagesState.value = MessagesState.Success(sortedMessages)

                        // If there are new messages and user is not active in chat, update chat list
                        if (!isInitialLoad && !isChatActive && sortedMessages.size > currentMessages.size) {
                            com.crm.chat.ui.main.MainViewModel.getInstance().notifyChatUpdated(chatId)
                        }
                    } else {
                        println("DEBUG: Messages unchanged, skipping UI update")
                    }
                },
                onFailure = { exception ->
                    // For initial load failures, still set success with empty list to avoid hanging
                    if (messagesState.value !is MessagesState.Success) {
                        println("DEBUG: Initial messages load failed, setting empty list to avoid hanging")
                        _messagesState.value = MessagesState.Success(emptyList())
                    } else if (messagesState.value !is MessagesState.Error) {
                        _messagesState.value = MessagesState.Error(exception.message ?: "Failed to load messages")
                    }
                }
            )
        }
    }

    fun setChatActive(active: Boolean) {
        isChatActive = active
    }

    fun sendMessage(text: String, replyToMessage: com.crm.chat.data.model.ChatMessage? = null, fileIds: List<String>? = null) {
        _sendMessageState.value = SendMessageState.Loading

        viewModelScope.launch {
            val request = SendMessageRequest(
                text = text,
                replyToId = replyToMessage?.id,
                fileIds = fileIds
            )
            val result = chatRepository.sendMessage(chatId, request)
            result.fold(
                onSuccess = { message ->
                    _sendMessageState.value = SendMessageState.Success(message)
                    // Reload messages to show the new message
                    loadMessages()
                },
                onFailure = { exception ->
                    _sendMessageState.value = SendMessageState.Error(exception.message ?: "Failed to send message")
                }
            )
        }
    }

    fun sendFileMessage(fileUri: android.net.Uri, contentResolver: android.content.ContentResolver) {
        _sendMessageState.value = SendMessageState.Loading

        viewModelScope.launch {
            try {
                // Upload file first
                val uploadResult = chatRepository.uploadFile(fileUri, contentResolver)
                uploadResult.fold(
                    onSuccess = { uploadedFiles ->
                        if (uploadedFiles.isNotEmpty()) {
                            val fileIds = uploadedFiles.map { it.id }
                            // Send message with file IDs
                            val request = SendMessageRequest(
                                text = "",
                                fileIds = fileIds
                            )
                            val messageResult = chatRepository.sendMessage(chatId, request)
                            messageResult.fold(
                                onSuccess = { message ->
                                    _sendMessageState.value = SendMessageState.Success(message)
                                    // Reload messages to show the new message
                                    loadMessages()
                                },
                                onFailure = { exception ->
                                    _sendMessageState.value = SendMessageState.Error(exception.message ?: "Failed to send file message")
                                }
                            )
                        } else {
                            _sendMessageState.value = SendMessageState.Error("No files uploaded")
                        }
                    },
                    onFailure = { exception ->
                        _sendMessageState.value = SendMessageState.Error(exception.message ?: "Failed to upload file")
                    }
                )
            } catch (e: Exception) {
                _sendMessageState.value = SendMessageState.Error(e.message ?: "Unexpected error")
            }
        }
    }

    fun markMessagesAsRead() {
        // Get current messages to find unread ones
        val currentMessages = messagesState.value
        if (currentMessages is MessagesState.Success) {
            val currentUserId = 12033923L // Hardcoded, should be from auth

            // Find unread messages (messages from other users that don't have "seen" status)
            val unreadMessageIds = currentMessages.messages
                .filter { message ->
                    message.chatUserId != currentUserId && // Not from current user
                    (message.statuses?.none { status ->
                        status.chatUserId == currentUserId && status.status == "seen"
                    } ?: true) // No "seen" status from current user (or no statuses at all)
                }
                .map { it.id }

            if (unreadMessageIds.isNotEmpty()) {
                viewModelScope.launch {
                    val result = chatRepository.markMessagesAsRead(chatId, unreadMessageIds)
                    result.fold(
                        onSuccess = {
                            // Messages marked as read, notify main view model to refresh chat list
                            // This will update the unseenCount in the chat list
                            com.crm.chat.ui.main.MainViewModel.getInstance().notifyChatUpdated(chatId)
                        },
                        onFailure = { exception ->
                            println("DEBUG: Failed to mark messages as read: ${exception.message}")
                        }
                    )
                }
            }
        }
    }

    fun refreshMessages() {
        // Force refresh messages by clearing previous messages cache
        previousMessages = emptyList()
        // Force reload by setting loading state and then loading
        _messagesState.value = MessagesState.Loading
        loadMessages()
    }

    private fun hasChatChanged(currentChat: Chat, newChat: Chat): Boolean {
        // Compare basic chat properties
        if (currentChat.id != newChat.id ||
            currentChat.title != newChat.title ||
            currentChat.type != newChat.type ||
            currentChat.createdAt != newChat.createdAt ||
            currentChat.updatedAt != newChat.updatedAt ||
            currentChat.unseenCount != newChat.unseenCount ||
            currentChat.hasAccess != newChat.hasAccess) {
            return true
        }

        // Compare users
        val currentUsers = currentChat.users ?: emptyList()
        val newUsers = newChat.users ?: emptyList()

        if (currentUsers.size != newUsers.size) {
            return true
        }

        for (i in 0 until currentUsers.size) {
            val currentUser = currentUsers[i]
            val newUser = newUsers.getOrNull(i) ?: return true
            if (currentUser.id != newUser.id ||
                currentUser.userId != newUser.userId ||
                currentUser.role != newUser.role) {
                return true
            }
        }

        // Compare last message if it exists
        val currentLastMessage = currentChat.lastMessage
        val newLastMessage = newChat.lastMessage

        if ((currentLastMessage == null) != (newLastMessage == null)) {
            return true // One has last message, other doesn't
        }

        if (currentLastMessage != null && newLastMessage != null) {
            if (currentLastMessage.id != newLastMessage.id ||
                currentLastMessage.text != newLastMessage.text ||
                currentLastMessage.chatUserId != newLastMessage.chatUserId ||
                currentLastMessage.createdAt != newLastMessage.createdAt) {
                return true
            }
        }

        // No changes detected
        return false
    }

    private fun hasMessagesChanged(currentMessages: List<ChatMessage>, newMessages: List<ChatMessage>): Boolean {
        // Check if the number of messages changed
        if (currentMessages.size != newMessages.size) {
            return true
        }

        // Check if any message content changed (ignore status updates as they don't affect display)
        for (i in currentMessages.indices) {
            val current = currentMessages[i]
            val new = newMessages[i]

            // Compare basic properties that affect message display
            if (current.id != new.id ||
                current.text != new.text ||
                current.chatUserId != new.chatUserId ||
                current.createdAt != new.createdAt) {
                return true
            }

            // Compare files (attachments)
            val currentFiles = current.files ?: emptyList()
            val newFiles = new.files ?: emptyList()

            if (currentFiles.size != newFiles.size) {
                return true
            }

            for (j in currentFiles.indices) {
                val currentFile = currentFiles[j]
                val newFile = newFiles[j]
                if (currentFile.id != newFile.id ||
                    currentFile.fileName != newFile.fileName ||
                    currentFile.fileType != newFile.fileType) {
                    return true
                }
            }

            // Compare replyTo if exists
            val currentReplyTo = current.replyTo
            val newReplyTo = new.replyTo

            if ((currentReplyTo == null) != (newReplyTo == null)) {
                return true // One has reply, other doesn't
            }

            if (currentReplyTo != null && newReplyTo != null) {
                if (currentReplyTo.id != newReplyTo.id ||
                    currentReplyTo.text != newReplyTo.text) {
                    return true
                }
            }

            // Compare reactions (this affects message display)
            val currentReactions = current.reactions ?: emptyList()
            val newReactions = new.reactions ?: emptyList()

            if (currentReactions.size != newReactions.size) {
                return true
            }

            // Compare reaction content (emoji and who reacted)
            val currentReactionsSorted = currentReactions.sortedBy { it.id }
            val newReactionsSorted = newReactions.sortedBy { it.id }

            for (k in currentReactionsSorted.indices) {
                val currentReaction = currentReactionsSorted[k]
                val newReaction = newReactionsSorted.getOrNull(k) ?: return true
                if (currentReaction.id != newReaction.id ||
                    currentReaction.reaction != newReaction.reaction ||
                    currentReaction.chatUserId != newReaction.chatUserId) {
                    return true
                }
            }

            // Note: We ignore status changes (seen/unseen) as they don't affect message display
        }

        // No content changes detected
        return false
    }

    private fun startPolling() {
        pollingJob = viewModelScope.launch {
            while (true) {
                delay(1000)
                loadMessages()
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        pollingJob?.cancel()
    }

    fun editMessage(messageId: Long, newText: String) {
        _editMessageState.value = EditMessageState.Loading

        viewModelScope.launch {
            val request = com.crm.chat.data.model.UpdateMessageRequest(text = newText)
            val result = chatRepository.updateMessage(chatId, messageId, request)
            result.fold(
                onSuccess = { updatedMessage ->
                    _editMessageState.value = EditMessageState.Success(updatedMessage)

                    // Reload messages to show the updated message
                    // Note: The backend should handle marking the message as unread for other users
                    loadMessages()
                },
                onFailure = { exception ->
                    _editMessageState.value = EditMessageState.Error(exception.message ?: "Failed to edit message")
                }
            )
        }
    }

    fun deleteMessage(messageId: Long) {
        _deleteMessageState.value = DeleteMessageState.Loading

        viewModelScope.launch {
            val result = chatRepository.deleteMessage(chatId, messageId)
            result.fold(
                onSuccess = {
                    _deleteMessageState.value = DeleteMessageState.Success
                    // Reload messages to reflect the deletion
                    loadMessages()
                },
                onFailure = { exception ->
                    _deleteMessageState.value = DeleteMessageState.Error(exception.message ?: "Failed to delete message")
                }
            )
        }
    }

    fun addReaction(messageId: Long, reaction: String) {
        // Validate that the reaction is one of the allowed emojis
        if (reaction !in ALLOWED_EMOJIS) {
            _reactionState.value = ReactionState.Error("Invalid reaction emoji")
            return
        }

        _reactionState.value = ReactionState.Loading

        viewModelScope.launch {
            val result = chatRepository.reactToMessage(chatId, messageId, reaction)
            result.fold(
                onSuccess = { updatedMessage ->
                    _reactionState.value = ReactionState.Success(updatedMessage)
                    // Force reload messages to show the updated reactions
                    // Clear previous messages cache to ensure update
                    previousMessages = emptyList()
                    loadMessages()
                },
                onFailure = { exception ->
                    _reactionState.value = ReactionState.Error(exception.message ?: "Failed to add reaction")
                }
            )
        }
    }

    fun removeReaction(messageId: Long, reactionId: Long) {
        _reactionState.value = ReactionState.Loading

        viewModelScope.launch {
            val result = chatRepository.unreactToMessage(chatId, messageId, reactionId)
            result.fold(
                onSuccess = { updatedMessage ->
                    _reactionState.value = ReactionState.Success(updatedMessage)
                    // Force reload messages to show the updated reactions
                    // Clear previous messages cache to ensure update
                    previousMessages = emptyList()
                    loadMessages()
                },
                onFailure = { exception ->
                    _reactionState.value = ReactionState.Error(exception.message ?: "Failed to remove reaction")
                }
            )
        }
    }
}
