@file:Suppress("HardCodedStringLiteral", "unused")

package eu.gaudian.translator.viewmodel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.gaudian.translator.utils.Log
import eu.gaudian.translator.utils.StatusAction
import eu.gaudian.translator.utils.StatusMessageId
import eu.gaudian.translator.utils.StatusMessageService
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.util.LinkedList
import java.util.Queue
import javax.inject.Inject

enum class MessageAction {
    NAVIGATE_TO_API_KEYS
}

sealed class StatusState {
    object Hidden : StatusState()
    object Loading : StatusState()
    data class Message(
        val id: Long,
        val text: String,
        val type: MessageDisplayType = MessageDisplayType.INFO,
        val action: MessageAction? = null
    ) : StatusState()
}

// Priorities are now more distinct to ensure clear hierarchy.
enum class MessageDisplayType(val priority: Int) {
    INFO(1),
    INTERN(1),
    LOADING(2),
    SUCCESS(3),
    ERROR(4),
    ACTIONABLE_ERROR(5)
}

/**
 * StatusViewModel is responsible for:
 * 1. Collecting status actions from StatusMessageService
 * 2. Managing the message queue
 * 3. Resolving StatusMessageId to actual strings
 * 4. Managing status state
 *
 * NOTE: All message display requests should go through StatusMessageService.
 * This ViewModel should NOT be called directly to display messages.
 */
@HiltViewModel
class StatusViewModel @Inject constructor(
    application: Application,
    private val statusMessageService: StatusMessageService
) : AndroidViewModel(application) {

    private val messageQueue: Queue<Pair<String, MessageDisplayType>> = LinkedList()
    private var messageDisplayJob: Job? = null
    private var activeLoadingJob: Job? = null
    private var messageIdCounter = 0L

    private val _status = MutableStateFlow<StatusState>(StatusState.Hidden)
    val status: StateFlow<StatusState> = _status.asStateFlow()

    init {
        viewModelScope.launch {
            statusMessageService.actions.collect { action ->
                handleAction(action)
            }
        }
    }

    /**
     * Handles all status actions from StatusMessageService.
     * This is the main entry point for all status messages.
     */
    private fun handleAction(action: StatusAction) {
        Log.d("StatusViewModel", "Received action: $action")
        when (action) {
            // Legacy string-based actions (deprecated but still supported for backward compatibility)
            is StatusAction.ShowMessage -> showMessageInternal(action.text, action.type, action.timeoutInSeconds)
            is StatusAction.ShowActionableMessage -> showPermanentActionableMessageInternal(action.text, action.type, action.action)
            is StatusAction.ShowPermanentMessage -> showPermanentMessageInternal(action.text, action.type)
            is StatusAction.PerformLoadingOperation -> performLoadingOperationInternal(action.block)
            is StatusAction.CancelLoadingOperation -> cancelLoadingOperationInternal()
            is StatusAction.CancelPermanentMessage -> cancelPermanentMessageInternal()
            is StatusAction.HideMessageBar -> hideMessageBarInternal()
            is StatusAction.CancelAllMessages -> cancelAllMessagesInternal()

            // New ID-based actions for internationalization
            is StatusAction.ShowMessageById -> showMessageByIdInternal(
                action.messageId,
                action.type,
                action.timeoutInSeconds
            )
            is StatusAction.ShowPermanentMessageById -> showPermanentMessageByIdInternal(
                action.messageId,
                action.type
            )
            is StatusAction.ShowActionableMessageById -> showPermanentActionableMessageByIdInternal(
                action.messageId,
                action.type,
                action.action
            )
        }
    }

    /**
     * Resolves a StatusMessageId to its actual string text using Android string resources.
     */
    private fun resolveMessageText(messageId: StatusMessageId): String {
        return try {
            getApplication<Application>().getString(messageId.stringResId)
        } catch (e: Exception) {
            Log.e("StatusViewModel", "Failed to resolve message string for ID: $messageId", e)
            "Message not available"
        }
    }

    // --- ID-based internal methods ---

    private fun showMessageByIdInternal(
        messageId: StatusMessageId,
        type: MessageDisplayType,
        timeoutInSeconds: Int
    ) {
        val text = resolveMessageText(messageId)
        showMessageInternal(text, type, timeoutInSeconds)
    }

    private fun showPermanentMessageByIdInternal(
        messageId: StatusMessageId,
        type: MessageDisplayType
    ) {
        val text = resolveMessageText(messageId)
        showPermanentMessageInternal(text, type)
    }

    private fun showPermanentActionableMessageByIdInternal(
        messageId: StatusMessageId,
        type: MessageDisplayType,
        action: MessageAction
    ) {
        val text = resolveMessageText(messageId)
        showPermanentActionableMessageInternal(text, type, action)
    }

    // --- Internal message display methods ---

    private fun showPermanentActionableMessageInternal(message: String, type: MessageDisplayType, action: MessageAction) {
        cancelAllOperations() // Clear any other messages or loaders.
        _status.value = StatusState.Message(messageIdCounter++, message, type, action)
    }

    private fun showPermanentMessageInternal(message: String, type: MessageDisplayType) {
        cancelAllOperations()
        _status.value = StatusState.Message(messageIdCounter++, message, type, action = null)
    }

    private fun performLoadingOperationInternal(block: suspend () -> Unit) {
        cancelAllOperations()
        _status.value = StatusState.Loading
        Log.d("StatusViewModel", "Starting loading operation.")
        activeLoadingJob = viewModelScope.launch {
            try {
                block()
                Log.d("StatusViewModel", "Loading operation completed successfully.")
            } catch (e: CancellationException) {
                Log.i("StatusViewModel", "Loading operation was cancelled.")
            } catch (e: Exception) {
                Log.e("StatusViewModel", "Loading operation failed.", e)
                // Trigger error message through StatusMessageService
                viewModelScope.launch {
                    statusMessageService.showErrorById(StatusMessageId.ERROR_OPERATION_FAILED)
                }
            } finally {
                if (activeLoadingJob == this.coroutineContext[Job]) {
                    if (_status.value == StatusState.Loading) {
                        _status.value = StatusState.Hidden
                    }
                    activeLoadingJob = null
                    processNextMessageInQueue()
                }
            }
        }
    }

    private fun cancelLoadingOperationInternal() {
        activeLoadingJob?.cancel()
        activeLoadingJob = null
        if (_status.value == StatusState.Loading || (_status.value as? StatusState.Message)?.type == MessageDisplayType.LOADING) {
            _status.value = StatusState.Hidden
            processNextMessageInQueue()
        }
    }

    private fun cancelPermanentMessageInternal() {
        if (_status.value is StatusState.Message) {
            _status.value = StatusState.Hidden
            processNextMessageInQueue()
        }
    }

    private fun hideMessageBarInternal() {
        messageDisplayJob?.cancel()
        messageDisplayJob = null
        if (_status.value is StatusState.Message) {
            _status.value = StatusState.Hidden
        }
        if (activeLoadingJob?.isActive != true) {
            processNextMessageInQueue()
        }
    }

    private fun cancelAllMessagesInternal() {
        Log.d("StatusViewModel", "Cancelling all messages.")
        messageQueue.clear()
        messageDisplayJob?.cancel()
        messageDisplayJob = null
        if (_status.value is StatusState.Message) {
            _status.value = StatusState.Hidden
        }
    }

    /**
     * Displays a message with priority-based queuing.
     * High-priority messages interrupt lower-priority ones.
     */
    private fun showMessageInternal(message: String, type: MessageDisplayType, timeoutInSeconds: Int) {
        val currentState = _status.value
        val currentPriority = (currentState as? StatusState.Message)?.type?.priority ?: -1

        // If a high-priority message arrives, it interrupts any lower-priority one.
        if (type.priority >= currentPriority) {
            messageDisplayJob?.cancel() // Cancel the current display job
            messageQueue.clear() // Clear pending lower-priority messages
            messageQueue.offer(Pair(message, type))
            processNextMessageInQueue(timeoutInSeconds)
        } else if (activeLoadingJob?.isActive != true) {
            // Queue if lower priority and no full-screen loading is active
            messageQueue.offer(Pair(message, type))
            if (currentState == StatusState.Hidden) {
                processNextMessageInQueue(timeoutInSeconds)
            }
        } else {
            Log.d("StatusViewModel", "Full-screen loading active or lower priority. Queuing message: $message")
            messageQueue.offer(Pair(message, type))
        }
    }

    private fun cancelAllOperations() {
        messageQueue.clear()
        messageDisplayJob?.cancel()
        messageDisplayJob = null
        activeLoadingJob?.cancel()
        activeLoadingJob = null
        _status.value = StatusState.Hidden
    }

    /**
     * Processes the next message in the queue.
     */
    private fun processNextMessageInQueue(timeoutInSeconds: Int = 3) {
        if (activeLoadingJob?.isActive == true) {
            Log.d("StatusViewModel", "Full-screen loading is active, not processing message queue now.")
            return
        }
        if (messageDisplayJob?.isActive == true) {
            // A message is already being displayed and its timeout is active.
            return
        }

        val messagePair = messageQueue.poll()
        if (messagePair != null) {
            val currentId = messageIdCounter++
            val (text, type) = messagePair
            _status.value = StatusState.Message(currentId, text, type)

            val timeoutMillis = timeoutInSeconds * 1000L

            if (timeoutMillis > 0) {
                messageDisplayJob = viewModelScope.launch {
                    delay(timeoutMillis)
                    // Ensure we are hiding the correct message before proceeding.
                    if ((_status.value as? StatusState.Message)?.id == currentId) {
                        _status.value = StatusState.Hidden
                        // After hiding, check if there's another message to show.
                        processNextMessageInQueue()
                    }
                }
            }
        } else {
            if (_status.value is StatusState.Message) {
                _status.value = StatusState.Hidden
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        Log.d("StatusViewModel", "onCleared called. Cancelling all operations.")
        cancelAllOperations()
    }
}
