package com.seven.ikar.kotlin.feature.share

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import com.seven.ikar.kotlin.core.contacts.DiscoverUserItem
import com.seven.ikar.kotlin.core.contacts.PhoneNumberNormalizer
import com.seven.ikar.kotlin.core.model.ChatSummaryDto
import com.seven.ikar.kotlin.core.model.ChatType
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

data class ShareTargetUiState(
    val payload: PendingExternalShare,
    val query: String = "",
    val contacts: List<DiscoverUserItem> = emptyList(),
    val isLoading: Boolean = false,
    val isSending: Boolean = false,
    val errorMessage: String? = null,
    val pendingChatId: String? = null
)

class ShareTargetViewModel(
    private val container: AppContainer,
    private val pendingShare: PendingExternalShare
) : ViewModel() {
    private val _uiState = MutableStateFlow(ShareTargetUiState(payload = pendingShare))
    private val _allChats = mutableListOf<ChatSummaryDto>()
    private var searchJob: Job? = null

    val uiState: StateFlow<ShareTargetUiState> = _uiState.asStateFlow()

    init {
        refresh()
    }

    fun updateQuery(value: String) {
        _uiState.value = _uiState.value.copy(query = value)
        searchJob?.cancel()
        searchJob = viewModelScope.launch {
            delay(250)
            refresh()
        }
    }

    fun refresh() {
        viewModelScope.launch {
            val query = _uiState.value.query.trim()
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching {
                val chats = container.executeAuthorized { session ->
                    container.apiClient.getChats(session.accessToken)
                }
                _allChats.clear()
                _allChats.addAll(chats)
                loadContactCandidates(query)
            }.onSuccess { contacts ->
                _uiState.value = _uiState.value.copy(
                    contacts = contacts,
                    isLoading = false,
                    errorMessage = null
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
            }
        }
    }

    fun sendToUser(user: DiscoverUserItem) {
        if (_uiState.value.isSending) {
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isSending = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    val existingChatId = findExistingDirectChatId(user.id)
                    val targetChatId = existingChatId ?: container.apiClient.createDirectChat(session.accessToken, user.id).id
                    sendPendingShare(session.accessToken, targetChatId)
                    targetChatId
                }
            }.onSuccess { chatId ->
                _uiState.value = _uiState.value.copy(isSending = false, pendingChatId = chatId)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isSending = false, errorMessage = error.message)
            }
        }
    }

    fun consumePendingChatNavigation() {
        _uiState.value = _uiState.value.copy(pendingChatId = null)
    }

    private suspend fun sendPendingShare(accessToken: String, chatId: String) {
        val sharedText = pendingShare.text?.trim().orEmpty()
        if (pendingShare.attachments.isEmpty()) {
            check(sharedText.isNotBlank()) { "Нечего отправлять." }
            container.apiClient.sendMessage(chatId, sharedText, accessToken)
            return
        }

        container.transferQueueRepository.enqueueUpload(
            chatId = chatId,
            text = sharedText.takeIf { it.isNotBlank() },
            replyToMessageId = null,
            files = pendingShare.attachments
        )
    }

    private suspend fun loadContactCandidates(query: String): List<DiscoverUserItem> {
        return when {
            hasContactsPermission() -> container.resolvedContactsRepository.loadMergedCandidates(query)
            query.isBlank() -> emptyList()
            else -> container.executeAuthorized { session ->
                container.apiClient.searchUsers(session.accessToken, query).map { user ->
                    DiscoverUserItem(
                        user = user,
                        displayName = user.displayName,
                        normalizedPhoneNumber = PhoneNumberNormalizer.normalize(user.phoneNumber) ?: ""
                    )
                }
            }
        }
    }

    private fun findExistingDirectChatId(userId: String): String? =
        _allChats.firstOrNull { chat ->
            chat.type == ChatType.Direct && chat.participants.any { participant -> participant.id == userId }
        }?.id

    private fun hasContactsPermission(): Boolean =
        ContextCompat.checkSelfPermission(
            container.appContext,
            Manifest.permission.READ_CONTACTS
        ) == PackageManager.PERMISSION_GRANTED
}
