package net.buzzert.kordophonedroid.ui.conversationlist

import android.util.Log
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophone.backend.server.APIClientFactory
import net.buzzert.kordophone.backend.server.ChatRepository
import net.buzzert.kordophonedroid.ui.shared.ServerConfigRepository
import javax.inject.Inject

const val CL_VM_LOG: String = "ConversationListViewModel"

@HiltViewModel
class ConversationListViewModel @Inject constructor(
    private val chatRepository: ChatRepository,
    private val serverConfigRepository: ServerConfigRepository,
) : ViewModel() {
    val conversations: Flow<List<Conversation>>
        get() = chatRepository.conversationChanges
            .shareIn(viewModelScope, started = SharingStarted.WhileSubscribed())
            .map {
                it.sortedBy { it.date }
                    .reversed()
            }

    val isServerConfigured: Boolean
        get() = chatRepository.isConfigured

    val encounteredConnectionError: State<Boolean>
        get() = _encounteredConnectionError

    private val _encounteredConnectionError = mutableStateOf(false)

    init {
        // Watch for config changes
        viewModelScope.launch {
            serverConfigRepository.serverConfig.collect { config ->
                Log.d(CL_VM_LOG, "Got settings change.")

                // Make new APIClient
                val baseURL = config.serverName
                val authentication = config.authentication?.toBackendAuthentication()
                val apiClient = APIClientFactory.createClient(baseURL, authentication)
                chatRepository.updateAPIClient(apiClient)

                // Perform db synchronization
                withContext(Dispatchers.IO) {
                    chatRepository.synchronize()
                }
            }
        }

        viewModelScope.launch {
            chatRepository.errorEncounteredChannel.collect {
                _encounteredConnectionError.value = true
            }
        }
    }

    suspend fun refresh() {
        chatRepository.synchronize()
    }
}