@file:OptIn(ExperimentalUuidApi::class)

package dev.zxq5.chatapp.android.feature.chat

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.zxq5.chatapp.android.api.model.ChatEvent
import dev.zxq5.chatapp.android.data.repository.ChatRepository
import dev.zxq5.chatapp.android.api.model.Message
import dev.zxq5.chatapp.android.api.model.SpaceDto
import dev.zxq5.chatapp.android.core.service.MessageStreamService
import io.ktor.client.plugins.ResponseException
import io.ktor.http.HttpStatusCode
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlin.time.ExperimentalTime
import kotlin.uuid.ExperimentalUuidApi

class ChatViewModel(private val chatRepository: ChatRepository) : ViewModel() {

    private val _messages = MutableStateFlow<List<Message>>(emptyList())
    val messages: StateFlow<List<Message>> = _messages

    private val _channelId = MutableStateFlow<Long?>(null)
    val channelId: StateFlow<Long?> = _channelId

    private val _currentScreen = MutableStateFlow(Screen.CHAT)
    val currentScreen: StateFlow<Screen> = _currentScreen

    private val _currentUserId = MutableStateFlow<Int?>(null)
    val currentUserId: StateFlow<Int?> = _currentUserId

    private val _spaces = MutableStateFlow<List<SpaceDto>>(emptyList())
    val spaces: StateFlow<List<SpaceDto>> = _spaces

    private val _error = MutableStateFlow<String?>(null)
    val error: StateFlow<String?> = _error

    private val _channelError = MutableStateFlow<String?>(null)
    val channelError: StateFlow<String?> = _channelError

    private var streamJob: Job? = null
    
    var onUnauthorized: (() -> Unit)? = null

    init {
        _currentUserId.value = chatRepository.getUserId()
        observeChannel()
        loadAccessibleChannels()
    }

    fun loadAccessibleChannels() {
        _error.value = null
        _currentUserId.value = chatRepository.getUserId()
        viewModelScope.launch {
            runCatching {
                chatRepository.getAccessibleChannels()
            }.onSuccess { data ->
                _spaces.value = data
            }.onFailure { e ->
                Log.e("Chat", "Failed to load spaces", e)
                if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
                    onUnauthorized?.invoke()
                } else {
                    _error.value = "Failed to load channels: ${e.message}"
                }
            }
        }
    }

    @OptIn(ExperimentalTime::class)
    private fun observeChannel() {
        viewModelScope.launch {
            _channelId.collect { id ->
                streamJob?.cancel()
                _messages.value = emptyList()
                _channelError.value = null
                if (id != null) {
                    streamJob = launch {
                        chatRepository.eventStream(id)
                            .catch { e -> 
                                Log.e("Chat", "Stream error", e)
                                if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
                                    onUnauthorized?.invoke()
                                } else {
                                    _channelError.value = "Connection lost: ${e.message}"
                                }
                            }
                            .collect { event ->
                                when (event) {
                                    is ChatEvent.SendMessage -> {
                                        _messages.update { it + event.data }
                                    }
                                    is ChatEvent.EditMessage -> {
                                        _messages.update { messages ->
                                            messages.map {
                                                if (it.id == event.data.id) event.data.message
                                                else it
                                            }
                                        }
                                    }
                                    is ChatEvent.MessageAppendContent -> {
                                        _messages.update { messages ->
                                            messages.map { msg ->
                                                if (msg.id == event.data.id) {
                                                    msg.copy(text = msg.text + event.data.content)
                                                } else {
                                                    msg
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                    }
                }
            }
        }
    }

    fun navigateTo(screen: Screen) {
        _currentScreen.value = screen
    }

    fun switchChannel(id: Long?) {
        _channelId.value = id

        MessageStreamService.instance?.activeChannelId = id

        if (id != null) {
            // Refresh user ID just in case it wasn't available at init
            _currentUserId.value = chatRepository.getUserId()
        }
    }

    fun sendMessage(text: String) {
        val currentId = _channelId.value ?: return
        viewModelScope.launch {
            runCatching {
                chatRepository.sendMessage(
                    channelId = currentId,
                    text = text
                )
            }.onFailure { e ->
                Log.e("Chat", "Send message error", e)
                if (e is ResponseException && e.response.status == HttpStatusCode.Unauthorized) {
                    onUnauthorized?.invoke()
                } else {
                    _channelError.value = "Failed to send message"
                }
            }
        }
    }
    
    fun clearChat() {
        _messages.value = emptyList()
        _channelId.value = null
        _currentUserId.value = null
        _spaces.value = emptyList()
        _error.value = null
        _channelError.value = null
        streamJob?.cancel()
        chatRepository.resetClient()
        MessageStreamService.instance?.activeChannelId = null
    }

    fun clearChannelError() {
        _channelError.value = null
    }
}
