package com.seven.ikar.kotlin.feature.discover

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import com.seven.ikar.kotlin.core.contacts.DiscoverUserItem
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.Locale

enum class DiscoverSelectionMode {
    Group,
    Channel
}

enum class ChannelWizardStep {
    Details,
    Type,
    Subscribers
}

enum class ChannelVisibility {
    Public,
    Private
}

data class DiscoverUiState(
    val query: String = "",
    val items: List<DiscoverUserItem> = emptyList(),
    val isLoading: Boolean = false,
    val errorMessage: String? = null,
    val pendingChatId: String? = null,
    val selectionMode: DiscoverSelectionMode? = null,
    val selectedUserIds: Set<String> = emptySet(),
    val channelWizardStep: ChannelWizardStep? = null,
    val channelTitle: String = "",
    val channelDescription: String = "",
    val channelVisibility: ChannelVisibility = ChannelVisibility.Private,
    val channelPublicUsername: String = "",
    val channelSignaturesEnabled: Boolean = false
)

class DiscoverViewModel(private val container: AppContainer) : ViewModel() {
    private val _uiState = MutableStateFlow(DiscoverUiState())
    val uiState: StateFlow<DiscoverUiState> = _uiState.asStateFlow()

    private var searchJob: Job? = null

    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
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching { container.resolvedContactsRepository.loadMergedCandidates(query) }
                .onSuccess { items ->
                    _uiState.value = _uiState.value.copy(items = items, isLoading = false, errorMessage = null)
                }
                .onFailure { error ->
                    _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
                }
        }
    }

    fun beginGroupSelection() {
        _uiState.value = _uiState.value.copy(
            selectionMode = DiscoverSelectionMode.Group,
            selectedUserIds = emptySet(),
            channelWizardStep = null,
            errorMessage = null
        )
    }

    fun beginChannelSelection() {
        _uiState.value = _uiState.value.copy(
            selectionMode = null,
            selectedUserIds = emptySet(),
            channelWizardStep = ChannelWizardStep.Details,
            channelTitle = "",
            channelDescription = "",
            channelVisibility = ChannelVisibility.Private,
            channelPublicUsername = "",
            channelSignaturesEnabled = false,
            errorMessage = null
        )
    }

    fun cancelSelection() {
        _uiState.value = _uiState.value.copy(
            selectionMode = null,
            selectedUserIds = emptySet(),
            channelWizardStep = null,
            errorMessage = null
        )
    }

    fun previousChannelWizardStep() {
        val state = _uiState.value
        when (state.channelWizardStep) {
            ChannelWizardStep.Details, null -> cancelSelection()
            ChannelWizardStep.Type -> _uiState.value = state.copy(channelWizardStep = ChannelWizardStep.Details, errorMessage = null)
            ChannelWizardStep.Subscribers -> _uiState.value = state.copy(
                channelWizardStep = ChannelWizardStep.Type,
                selectionMode = null,
                selectedUserIds = emptySet(),
                errorMessage = null
            )
        }
    }

    fun updateChannelTitle(value: String) {
        _uiState.value = _uiState.value.copy(channelTitle = value.take(80), errorMessage = null)
    }

    fun updateChannelDescription(value: String) {
        _uiState.value = _uiState.value.copy(channelDescription = value.take(255), errorMessage = null)
    }

    fun updateChannelVisibility(value: ChannelVisibility) {
        _uiState.value = _uiState.value.copy(channelVisibility = value, errorMessage = null)
    }

    fun updateChannelPublicUsername(value: String) {
        val normalized = normalizePublicUsernameInput(value)
        _uiState.value = _uiState.value.copy(channelPublicUsername = normalized, errorMessage = null)
    }

    fun updateChannelSignaturesEnabled(value: Boolean) {
        _uiState.value = _uiState.value.copy(channelSignaturesEnabled = value, errorMessage = null)
    }

    fun continueChannelWizard() {
        val state = _uiState.value
        when (state.channelWizardStep) {
            ChannelWizardStep.Details -> {
                if (state.channelTitle.isBlank()) {
                    _uiState.value = state.copy(errorMessage = "Введите название канала.")
                    return
                }
                _uiState.value = state.copy(channelWizardStep = ChannelWizardStep.Type, errorMessage = null)
            }

            ChannelWizardStep.Type -> {
                if (state.channelVisibility == ChannelVisibility.Public && state.channelPublicUsername.length < 5) {
                    _uiState.value = state.copy(errorMessage = "Публичная ссылка должна содержать минимум 5 символов.")
                    return
                }
                _uiState.value = state.copy(
                    channelWizardStep = ChannelWizardStep.Subscribers,
                    selectionMode = DiscoverSelectionMode.Channel,
                    selectedUserIds = emptySet(),
                    errorMessage = null
                )
            }

            ChannelWizardStep.Subscribers -> completeSelection()
            null -> Unit
        }
    }

    fun handleUserTap(user: DiscoverUserItem) {
        val selectionMode = _uiState.value.selectionMode
        if (selectionMode == null) {
            startDirectChat(user)
            return
        }

        val selected = _uiState.value.selectedUserIds.toMutableSet()
        if (!selected.add(user.id)) {
            selected.remove(user.id)
        }
        _uiState.value = _uiState.value.copy(selectedUserIds = selected, errorMessage = null)
    }

    fun completeSelection() {
        val mode = _uiState.value.selectionMode ?: return
        val state = _uiState.value
        val selectedIds = state.selectedUserIds.toList()
        if (mode == DiscoverSelectionMode.Group && selectedIds.isEmpty()) {
            _uiState.value = state.copy(errorMessage = "Выберите хотя бы одного участника.")
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isLoading = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    when (mode) {
                        DiscoverSelectionMode.Group -> container.apiClient.createGroupChat(
                            accessToken = session.accessToken,
                            title = "Новая группа",
                            memberIds = selectedIds
                        )

                        DiscoverSelectionMode.Channel -> container.apiClient.createChannel(
                            accessToken = session.accessToken,
                            title = state.channelTitle.trim(),
                            memberIds = selectedIds,
                            description = state.channelDescription.trim().takeIf { it.isNotEmpty() },
                            publicUsername = state.channelPublicUsername.takeIf { state.channelVisibility == ChannelVisibility.Public },
                            createInviteLink = state.channelVisibility == ChannelVisibility.Private,
                            channelSignaturesEnabled = state.channelSignaturesEnabled
                        )
                    }
                }
            }.onSuccess { chat ->
                _uiState.value = _uiState.value.copy(
                    pendingChatId = chat.id,
                    isLoading = false,
                    selectionMode = null,
                    selectedUserIds = emptySet(),
                    channelWizardStep = null,
                    errorMessage = null
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(isLoading = false, errorMessage = error.message)
            }
        }
    }

    fun startDirectChat(user: DiscoverUserItem) {
        viewModelScope.launch {
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.createDirectChat(session.accessToken, user.id)
                }
            }.onSuccess { chat ->
                _uiState.value = _uiState.value.copy(pendingChatId = chat.id)
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(errorMessage = error.message)
            }
        }
    }

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

    private fun normalizePublicUsernameInput(value: String): String =
        value
            .trim()
            .trimStart('@')
            .filter { it in 'a'..'z' || it in 'A'..'Z' || it.isDigit() || it == '_' }
            .take(32)
            .lowercase(Locale.US)
}
