package com.seven.ikar.kotlin.feature.members

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.seven.ikar.kotlin.app.AppContainer
import com.seven.ikar.kotlin.core.model.AddChatMembersRequest
import com.seven.ikar.kotlin.core.model.ChatDetailsDto
import com.seven.ikar.kotlin.core.model.ChatJoinRequestDto
import com.seven.ikar.kotlin.core.model.ChatMemberDto
import com.seven.ikar.kotlin.core.model.ChatMemberRole
import com.seven.ikar.kotlin.core.model.ChatType
import com.seven.ikar.kotlin.core.model.ModerationLogDto
import com.seven.ikar.kotlin.core.model.UpdateChatMemberPermissionsRequest
import com.seven.ikar.kotlin.core.model.UserSummaryDto
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 ChatMembersUiState(
    val chat: ChatDetailsDto? = null,
    val joinRequests: List<ChatJoinRequestDto> = emptyList(),
    val moderationLog: List<ModerationLogDto> = emptyList(),
    val isLoading: Boolean = false,
    val isAdminPanelLoading: Boolean = false,
    val memberSearchQuery: String = "",
    val memberSearchResults: List<UserSummaryDto> = emptyList(),
    val isMemberSearchLoading: Boolean = false,
    val addingUserIds: Set<String> = emptySet(),
    val updatingUserIds: Set<String> = emptySet(),
    val resolvingJoinRequestIds: Set<String> = emptySet(),
    val errorMessage: String? = null
) {
    val canManageMembers: Boolean
        get() = chat?.currentUserPermissions?.canManageMembers == true

    val canAddMembers: Boolean
        get() = canManageMembers && chat?.type == ChatType.Channel
}

class ChatMembersViewModel(
    private val container: AppContainer,
    private val chatId: String
) : ViewModel() {
    private val _uiState = MutableStateFlow(ChatMembersUiState())
    val uiState: StateFlow<ChatMembersUiState> = _uiState.asStateFlow()
    private var memberSearchJob: Job? = null

    init {
        refresh()
    }

    fun refresh() {
        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(isLoading = true, isAdminPanelLoading = true, errorMessage = null)
            runCatching {
                container.executeAuthorized { session ->
                    val chat = container.apiClient.getChat(chatId, session.accessToken)
                    val canManageMembers = chat.currentUserPermissions?.canManageMembers == true
                    ChatMembersPayload(
                        chat = chat,
                        joinRequests = if (canManageMembers) {
                            container.apiClient.getChatJoinRequests(session.accessToken, chatId)
                        } else {
                            emptyList()
                        },
                        moderationLog = if (canManageMembers) {
                            container.apiClient.getChatModerationLog(session.accessToken, chatId)
                        } else {
                            emptyList()
                        }
                    )
                }
            }.onSuccess { payload ->
                _uiState.value = _uiState.value.copy(
                    chat = payload.chat,
                    joinRequests = payload.joinRequests,
                    moderationLog = payload.moderationLog,
                    memberSearchResults = filterMemberSearchResults(_uiState.value.memberSearchResults, payload.chat),
                    isLoading = false,
                    isAdminPanelLoading = false,
                    errorMessage = null
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(
                    isLoading = false,
                    isAdminPanelLoading = false,
                    errorMessage = error.message
                )
            }
        }
    }

    fun updateMemberSearchQuery(value: String) {
        val query = value.take(80)
        _uiState.value = _uiState.value.copy(memberSearchQuery = query, errorMessage = null)
        memberSearchJob?.cancel()

        if (query.trim().length < 2 || !_uiState.value.canAddMembers) {
            _uiState.value = _uiState.value.copy(memberSearchResults = emptyList(), isMemberSearchLoading = false)
            return
        }

        memberSearchJob = viewModelScope.launch {
            delay(250)
            searchMembers(query.trim())
        }
    }

    fun addMember(user: UserSummaryDto, asAdmin: Boolean) {
        val state = _uiState.value
        if (!state.canAddMembers || state.addingUserIds.contains(user.id)) {
            return
        }

        val role = if (asAdmin) ChatMemberRole.Admin else ChatMemberRole.Member
        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(
                addingUserIds = _uiState.value.addingUserIds + user.id,
                errorMessage = null
            )
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.addChatMembers(
                        accessToken = session.accessToken,
                        chatId = chatId,
                        request = AddChatMembersRequest(
                            memberIds = listOf(user.id),
                            role = role,
                            canPinMessages = asAdmin,
                            canDeleteMessages = asAdmin,
                            canInviteUsers = asAdmin,
                            canPostMessages = asAdmin
                        )
                    )
                }
            }.onSuccess { chat ->
                val current = _uiState.value
                _uiState.value = current.copy(
                    chat = chat,
                    addingUserIds = current.addingUserIds - user.id,
                    memberSearchResults = filterMemberSearchResults(current.memberSearchResults, chat)
                )
                refresh()
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(
                    addingUserIds = _uiState.value.addingUserIds - user.id,
                    errorMessage = error.message
                )
            }
        }
    }

    fun approveJoinRequest(request: ChatJoinRequestDto) {
        resolveJoinRequest(request, approve = true)
    }

    fun declineJoinRequest(request: ChatJoinRequestDto) {
        resolveJoinRequest(request, approve = false)
    }

    fun toggleAdmin(member: ChatMemberDto) {
        val nextRole = if (member.role == ChatMemberRole.Admin) ChatMemberRole.Member else ChatMemberRole.Admin
        updateMember(member, role = nextRole)
    }

    fun toggleCanPost(member: ChatMemberDto) {
        updateMember(member, canPostMessages = !member.permissions.canPostMessages)
    }

    fun toggleCanPin(member: ChatMemberDto) {
        updateMember(member, canPinMessages = !member.permissions.canPinMessages)
    }

    fun toggleCanDelete(member: ChatMemberDto) {
        updateMember(member, canDeleteMessages = !member.permissions.canDeleteMessages)
    }

    fun toggleCanInvite(member: ChatMemberDto) {
        updateMember(member, canInviteUsers = !member.permissions.canInviteUsers)
    }

    private fun updateMember(
        member: ChatMemberDto,
        role: ChatMemberRole = member.role,
        canPostMessages: Boolean = member.permissions.canPostMessages,
        canPinMessages: Boolean = member.permissions.canPinMessages,
        canDeleteMessages: Boolean = member.permissions.canDeleteMessages,
        canInviteUsers: Boolean = member.permissions.canInviteUsers
    ) {
        if (member.isOwner || _uiState.value.updatingUserIds.contains(member.user.id)) {
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(
                updatingUserIds = _uiState.value.updatingUserIds + member.user.id,
                errorMessage = null
            )
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.updateChatMemberPermissions(
                        accessToken = session.accessToken,
                        chatId = chatId,
                        memberUserId = member.user.id,
                        request = UpdateChatMemberPermissionsRequest(
                            role = role,
                            canPinMessages = canPinMessages,
                            canDeleteMessages = canDeleteMessages,
                            canInviteUsers = canInviteUsers,
                            canPostMessages = canPostMessages
                        )
                    )
                }
            }.onSuccess { chat ->
                _uiState.value = _uiState.value.copy(
                    chat = chat,
                    updatingUserIds = _uiState.value.updatingUserIds - member.user.id
                )
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(
                    updatingUserIds = _uiState.value.updatingUserIds - member.user.id,
                    errorMessage = error.message
                )
            }
        }
    }

    private suspend fun searchMembers(query: String) {
        _uiState.value = _uiState.value.copy(isMemberSearchLoading = true, errorMessage = null)
        runCatching {
            container.executeAuthorized { session ->
                container.apiClient.searchUsers(session.accessToken, query)
            }
        }.onSuccess { users ->
            val current = _uiState.value
            _uiState.value = current.copy(
                memberSearchResults = filterMemberSearchResults(users, current.chat),
                isMemberSearchLoading = false
            )
        }.onFailure { error ->
            _uiState.value = _uiState.value.copy(
                isMemberSearchLoading = false,
                errorMessage = error.message
            )
        }
    }

    private fun filterMemberSearchResults(users: List<UserSummaryDto>, chat: ChatDetailsDto?): List<UserSummaryDto> {
        val memberIds = chat?.members.orEmpty().mapTo(mutableSetOf()) { it.user.id }
        return users.filterNot { user -> memberIds.contains(user.id) }
    }

    private fun resolveJoinRequest(request: ChatJoinRequestDto, approve: Boolean) {
        if (_uiState.value.resolvingJoinRequestIds.contains(request.id)) {
            return
        }

        viewModelScope.launch {
            _uiState.value = _uiState.value.copy(
                resolvingJoinRequestIds = _uiState.value.resolvingJoinRequestIds + request.id,
                errorMessage = null
            )
            runCatching {
                container.executeAuthorized { session ->
                    container.apiClient.resolveChatJoinRequest(
                        accessToken = session.accessToken,
                        chatId = chatId,
                        joinRequestId = request.id,
                        approve = approve
                    )
                }
            }.onSuccess {
                _uiState.value = _uiState.value.copy(
                    resolvingJoinRequestIds = _uiState.value.resolvingJoinRequestIds - request.id
                )
                refresh()
            }.onFailure { error ->
                _uiState.value = _uiState.value.copy(
                    resolvingJoinRequestIds = _uiState.value.resolvingJoinRequestIds - request.id,
                    errorMessage = error.message
                )
            }
        }
    }
}

private data class ChatMembersPayload(
    val chat: ChatDetailsDto,
    val joinRequests: List<ChatJoinRequestDto>,
    val moderationLog: List<ModerationLogDto>
)
