package de.trainingstagebuch.app.viewmodel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import de.trainingstagebuch.app.R
import de.trainingstagebuch.app.repository.PermissionActionResult
import de.trainingstagebuch.app.repository.PermissionMemberItem
import de.trainingstagebuch.app.repository.PermissionMembersResult
import de.trainingstagebuch.app.repository.PermissionResourceItem
import de.trainingstagebuch.app.repository.PermissionRolesResult
import de.trainingstagebuch.app.repository.PermissionStructureResult
import de.trainingstagebuch.app.services.AppServices
import de.trainingstagebuch.app.utils.ErrorMessageFormatter
import de.trainingstagebuch.app.utils.UiText
import de.trainingstagebuch.app.utils.ViewModelStateUtils
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

class PermissionsViewModel(application: Application) : AndroidViewModel(application) {
    private val authService = AppServices.authService
    private val permissionsService = AppServices.permissionsService

    private val _state = MutableStateFlow(PermissionsUiState())
    val state: StateFlow<PermissionsUiState> = _state.asStateFlow()

    init {
        load()
    }

    fun load(force: Boolean = false) {
        viewModelScope.launch {
            val clubId = resolveClubId() ?: return@launch
            _state.update {
                it.copy(
                    loading = true,
                    errorMessage = null,
                    successMessage = null
                )
            }

            val roles = when (val result = permissionsService.loadRoles()) {
                is PermissionRolesResult.Success -> result.items
                is PermissionRolesResult.Error -> {
                    showError(result.message, result.code)
                    return@launch
                }
            }

            val structure = when (val result = permissionsService.loadStructure()) {
                is PermissionStructureResult.Success -> result.items
                is PermissionStructureResult.Error -> {
                    showError(result.message, result.code)
                    return@launch
                }
            }

            val members = when (
                val result = permissionsService.loadMembers(
                    clubId = clubId,
                    cacheBust = if (force) System.currentTimeMillis() else null
                )
            ) {
                is PermissionMembersResult.Success -> result.items
                is PermissionMembersResult.Error -> {
                    showError(result.message, result.code)
                    return@launch
                }
            }

            _state.update {
                it.copy(
                    loading = false,
                    roles = roles,
                    structure = structure,
                    members = members,
                    selectedMember = it.selectedMember?.let { selected ->
                        members.firstOrNull { member -> member.userId == selected.userId }
                    }
                )
            }
        }
    }

    fun updateRole(member: PermissionMemberItem, role: String) {
        viewModelScope.launch {
            val clubId = resolveClubId() ?: return@launch
            when (val result = permissionsService.updateRole(clubId = clubId, userId = member.userId, role = role)) {
                is PermissionActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.permissions_role_updated)
                            )
                        )
                    }
                    load(force = true)
                }

                is PermissionActionResult.Error -> showError(result.message, result.code)
            }
        }
    }

    fun toggleStatus(member: PermissionMemberItem) {
        viewModelScope.launch {
            val clubId = resolveClubId() ?: return@launch
            val approved = !member.approved
            when (
                val result = permissionsService.updateStatus(
                    clubId = clubId,
                    userId = member.userId,
                    approved = approved
                )
            ) {
                is PermissionActionResult.Success -> {
                    _state.update {
                        it.copy(
                            members = it.members.map { existing ->
                                if (existing.userId == member.userId) existing.copy(approved = approved) else existing
                            },
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.permissions_status_updated)
                            )
                        )
                    }
                }

                is PermissionActionResult.Error -> showError(result.message, result.code)
            }
        }
    }

    fun openPermissionEditor(member: PermissionMemberItem) {
        val map = mutableMapOf<String, MutableMap<String, Boolean?>>()
        _state.value.structure.forEach { (resourceKey, resource) ->
            val overrides = member.permissions[resourceKey].orEmpty()
            val resourceMap = mutableMapOf<String, Boolean?>()
            resource.actions.forEach { action ->
                resourceMap[action] = overrides[action]
            }
            map[resourceKey] = resourceMap
        }
        _state.update {
            it.copy(
                selectedMember = member,
                permissionEditor = map
            )
        }
    }

    fun closePermissionEditor() {
        _state.update {
            it.copy(
                selectedMember = null,
                permissionEditor = emptyMap()
            )
        }
    }

    fun togglePermission(resource: String, action: String) {
        val selected = _state.value.selectedMember ?: return
        val effective = selected.effectivePermissions[resource]?.get(action) ?: false
        _state.update { current ->
            val currentResource = current.permissionEditor[resource].orEmpty().toMutableMap()
            val currentValue = currentResource[action]
            currentResource[action] = if (currentValue == null) !effective else null
            current.copy(
                permissionEditor = current.permissionEditor.toMutableMap().apply {
                    put(resource, currentResource)
                }
            )
        }
    }

    fun resetResource(resource: String) {
        _state.update { current ->
            val currentResource = current.permissionEditor[resource].orEmpty()
            val reset = currentResource.keys.associateWith { null }
            current.copy(
                permissionEditor = current.permissionEditor.toMutableMap().apply {
                    put(resource, reset)
                }
            )
        }
    }

    fun saveCustomPermissions() {
        val member = _state.value.selectedMember ?: return
        viewModelScope.launch {
            val clubId = resolveClubId() ?: return@launch
            val payload = _state.value.permissionEditor.mapValuesNotNull { (_, resourceActions) ->
                val cleaned = resourceActions.mapValuesNotNull { (_, value) -> value }
                if (cleaned.isEmpty()) null else cleaned
            }
            when (
                val result = permissionsService.updatePermissions(
                    clubId = clubId,
                    userId = member.userId,
                    permissions = payload
                )
            ) {
                is PermissionActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.permissions_saved)
                            )
                        )
                    }
                    closePermissionEditor()
                    load(force = true)
                }

                is PermissionActionResult.Error -> showError(result.message, result.code)
            }
        }
    }

    private suspend fun resolveClubId(): String? {
        val clubId = authService.session.first().currentClub?.trim().orEmpty()
        if (clubId.isBlank()) {
            _state.update {
                it.copy(
                    loading = false,
                    errorMessage = UiText(R.string.error_no_current_club)
                )
            }
            return null
        }
        return clubId
    }

    private fun showError(message: String?, code: String?) {
        _state.update {
            it.copy(
                loading = false,
                errorMessage = ViewModelStateUtils.normalizeUiText(
                    ErrorMessageFormatter.dynamicWithOptionalCode(message, code)
                )
            )
        }
    }
}

private inline fun <K, V, R : Any> Map<K, V>.mapValuesNotNull(transform: (Map.Entry<K, V>) -> R?): Map<K, R> {
    return entries.mapNotNull { entry ->
        transform(entry)?.let { mapped -> entry.key to mapped }
    }.toMap()
}

data class PermissionsUiState(
    val loading: Boolean = false,
    val roles: List<de.trainingstagebuch.app.repository.PermissionRoleItem> = emptyList(),
    val structure: Map<String, PermissionResourceItem> = emptyMap(),
    val members: List<PermissionMemberItem> = emptyList(),
    val selectedMember: PermissionMemberItem? = null,
    val permissionEditor: Map<String, Map<String, Boolean?>> = emptyMap(),
    val errorMessage: UiText? = null,
    val successMessage: UiText? = null
)
