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.DomainSocketEventType
import de.trainingstagebuch.app.repository.MemberItem
import de.trainingstagebuch.app.repository.MembersResult
import de.trainingstagebuch.app.repository.TournamentActionResult
import de.trainingstagebuch.app.repository.TournamentDetailResult
import de.trainingstagebuch.app.repository.TournamentItem
import de.trainingstagebuch.app.repository.TournamentListResult
import de.trainingstagebuch.app.repository.TournamentMatchItem
import de.trainingstagebuch.app.repository.TournamentMatchesResult
import de.trainingstagebuch.app.repository.TournamentParticipantItem
import de.trainingstagebuch.app.repository.TournamentParticipantsResult
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 TournamentTabViewModel(application: Application) : AndroidViewModel(application) {
    private val authService = AppServices.authService
    private val tournamentService = AppServices.tournamentService

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

    init {
        observeSocketEvents()
    }

    fun setMode(mode: TournamentMode) {
        if (_state.value.mode == mode && _state.value.tournaments.isNotEmpty()) return
        _state.update { TournamentTabUiState(mode = mode) }
        loadTournaments()
    }

    fun retry() = loadTournaments()

    fun onNewTournamentNameChanged(value: String) = _state.update { it.copy(newTournamentName = value) }
    fun onNewDateChanged(value: String) = _state.update { it.copy(newDate = value) }
    fun onNewWinningSetsChanged(value: String) = _state.update { it.copy(newWinningSets = value) }
    fun onNewMiniLocationChanged(value: String) = _state.update { it.copy(newMiniLocation = value) }
    fun onNewMiniYearChanged(value: String) = _state.update { it.copy(newMiniYear = value) }
    fun onSelectedMemberIdChanged(value: String?) = _state.update { it.copy(selectedMemberIdForAdd = value) }
    fun onEditNameChanged(value: String) = _state.update { it.copy(editName = value) }
    fun onEditDateChanged(value: String) = _state.update { it.copy(editDate = value) }
    fun onEditWinningSetsChanged(value: String) = _state.update { it.copy(editWinningSets = value) }
    fun onEditNumberOfTablesChanged(value: String) = _state.update { it.copy(editNumberOfTables = value) }
    fun onEditIsGroupChanged(value: Boolean) = _state.update { it.copy(editIsGroupTournament = value) }

    fun selectTournament(tournamentId: String?) {
        _state.update { it.copy(selectedTournamentId = tournamentId) }
        if (tournamentId.isNullOrBlank()) return
        loadSelectedTournamentData(tournamentId)
    }

    fun createTournament() {
        val name = _state.value.newTournamentName.trim()
        val date = _state.value.newDate.trim()
        val winningSets = _state.value.newWinningSets.toIntOrNull() ?: 3
        if (name.isBlank() || date.isBlank()) {
            _state.update { it.copy(errorMessage = UiText(R.string.tournament_create_invalid)) }
            return
        }
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val result = tournamentService.createTournament(clubId, name, date, winningSets)) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_created)),
                            newTournamentName = "",
                            newDate = "",
                            newWinningSets = "3"
                        )
                    }
                    loadTournaments()
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    fun createMiniTournament() {
        val location = _state.value.newMiniLocation.trim()
        val date = _state.value.newDate.trim()
        val year = _state.value.newMiniYear.toIntOrNull() ?: return
        val winningSets = _state.value.newWinningSets.toIntOrNull() ?: 3
        if (location.isBlank() || date.isBlank()) {
            _state.update { it.copy(errorMessage = UiText(R.string.tournament_create_invalid)) }
            return
        }
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val result = tournamentService.createMiniTournament(clubId, location, date, year, winningSets)) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_created))
                        )
                    }
                    loadTournaments()
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    fun saveConfig() {
        val tournamentId = _state.value.selectedTournamentId ?: return
        val name = _state.value.editName.trim()
        if (name.isBlank()) {
            _state.update { it.copy(errorMessage = UiText(R.string.tournament_config_invalid)) }
            return
        }
        val winningSets = _state.value.editWinningSets.toIntOrNull() ?: 3
        val tables = _state.value.editNumberOfTables.toIntOrNull()
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (
                val result = tournamentService.updateTournamentConfig(
                    clubId = clubId,
                    tournamentId = tournamentId,
                    name = name,
                    date = _state.value.editDate.trim().ifBlank { null },
                    winningSets = winningSets,
                    numberOfTables = tables,
                    isGroupTournament = _state.value.editIsGroupTournament
                )
            ) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_saved))
                        )
                    }
                    loadSelectedTournamentData(tournamentId)
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    fun addParticipant() {
        val tournamentId = _state.value.selectedTournamentId ?: return
        val memberId = _state.value.selectedMemberIdForAdd ?: return
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val result = tournamentService.addParticipant(clubId, tournamentId, memberId)) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            selectedMemberIdForAdd = null,
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_participant_added))
                        )
                    }
                    loadParticipantsAndMatches(tournamentId)
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    fun removeParticipant(participantId: String) {
        val tournamentId = _state.value.selectedTournamentId ?: return
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val result = tournamentService.removeParticipant(clubId, tournamentId, participantId)) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_participant_removed))
                        )
                    }
                    loadParticipantsAndMatches(tournamentId)
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    fun onMatchResultDraftChanged(matchId: String, value: String) {
        _state.update { state ->
            state.copy(matchResultDrafts = state.matchResultDrafts + (matchId to value))
        }
    }

    fun saveMatchResult(matchId: String) {
        val tournamentId = _state.value.selectedTournamentId ?: return
        val resultValue = _state.value.matchResultDrafts[matchId]?.trim().orEmpty()
        if (!resultValue.contains(":")) {
            _state.update { it.copy(errorMessage = UiText(R.string.tournament_result_invalid)) }
            return
        }
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val result = tournamentService.saveMatchResult(clubId, tournamentId, matchId, resultValue)) {
                is TournamentActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.tournament_result_saved))
                        )
                    }
                    loadParticipantsAndMatches(tournamentId)
                }

                is TournamentActionResult.Error -> emitError(result.code, result.message)
            }
        }
    }

    private fun loadTournaments() {
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) {
                _state.update { it.copy(errorMessage = UiText(R.string.error_no_current_club)) }
                return@launch
            }
            _state.update { it.copy(loading = true, errorMessage = null) }
            val type = when (_state.value.mode) {
                TournamentMode.Mini -> "mini"
                TournamentMode.External -> "external"
                TournamentMode.Internal -> null
            }
            when (val result = tournamentService.loadTournaments(clubId, type = type)) {
                is TournamentListResult.Success -> {
                    val firstId = result.items.firstOrNull()?.id
                    _state.update {
                        it.copy(
                            loading = false,
                            tournaments = result.items,
                            selectedTournamentId = it.selectedTournamentId ?: firstId
                        )
                    }
                    _state.value.selectedTournamentId?.let { id ->
                        loadSelectedTournamentData(id)
                    }
                }

                is TournamentListResult.Error -> emitError(result.code, result.message, loading = false)
            }
        }
    }

    private fun loadSelectedTournamentData(tournamentId: String) {
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            _state.update { it.copy(detailLoading = true, errorMessage = null) }
            when (val detail = tournamentService.loadTournament(clubId, tournamentId)) {
                is TournamentDetailResult.Success -> {
                    _state.update {
                        it.copy(
                            detailLoading = false,
                            tournamentDetail = detail.item,
                            editName = detail.item.name,
                            editDate = detail.item.date.orEmpty(),
                            editWinningSets = detail.item.winningSets.toString(),
                            editNumberOfTables = detail.item.numberOfTables?.toString().orEmpty(),
                            editIsGroupTournament = detail.item.isGroupTournament
                        )
                    }
                    loadParticipantsAndMatches(tournamentId)
                    loadMembers(clubId)
                }

                is TournamentDetailResult.Error -> emitError(detail.code, detail.message, loading = false, detailLoading = false)
            }
        }
    }

    private fun loadParticipantsAndMatches(tournamentId: String) {
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            when (val participants = tournamentService.loadParticipants(clubId, tournamentId)) {
                is TournamentParticipantsResult.Success -> {
                    _state.update { it.copy(participants = participants.items) }
                }

                is TournamentParticipantsResult.Error -> emitError(participants.code, participants.message)
            }
            when (val matches = tournamentService.loadMatches(clubId, tournamentId)) {
                is TournamentMatchesResult.Success -> {
                    _state.update { state ->
                        val drafts = matches.items.associate { it.id to (state.matchResultDrafts[it.id] ?: it.result.orEmpty()) }
                        state.copy(matches = matches.items, matchResultDrafts = drafts)
                    }
                }

                is TournamentMatchesResult.Error -> emitError(matches.code, matches.message)
            }
        }
    }

    private fun loadMembers(clubId: String) {
        viewModelScope.launch {
            when (val members = tournamentService.loadMembers(clubId)) {
                is MembersResult.Success -> {
                    _state.update { it.copy(clubMembers = members.members.filter { member -> member.active }) }
                }

                is MembersResult.Error -> {
                    _state.update {
                        it.copy(
                            errorMessage = ViewModelStateUtils.normalizeUiText(
                                ErrorMessageFormatter.dynamicWithOptionalCode(members.message, null)
                            )
                        )
                    }
                }
            }
        }
    }

    private fun observeSocketEvents() {
        viewModelScope.launch {
            tournamentService.socketEvents.collect { event ->
                if (event.type == DomainSocketEventType.TournamentChanged) {
                    loadTournaments()
                }
            }
        }
    }

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

data class TournamentTabUiState(
    val mode: TournamentMode = TournamentMode.Internal,
    val loading: Boolean = false,
    val detailLoading: Boolean = false,
    val tournaments: List<TournamentItem> = emptyList(),
    val selectedTournamentId: String? = null,
    val tournamentDetail: TournamentItem? = null,
    val participants: List<TournamentParticipantItem> = emptyList(),
    val matches: List<TournamentMatchItem> = emptyList(),
    val clubMembers: List<MemberItem> = emptyList(),
    val selectedMemberIdForAdd: String? = null,
    val newTournamentName: String = "",
    val newDate: String = "",
    val newWinningSets: String = "3",
    val newMiniLocation: String = "",
    val newMiniYear: String = "2026",
    val editName: String = "",
    val editDate: String = "",
    val editWinningSets: String = "3",
    val editNumberOfTables: String = "",
    val editIsGroupTournament: Boolean = false,
    val matchResultDrafts: Map<String, String> = emptyMap(),
    val errorMessage: UiText? = null,
    val successMessage: UiText? = null
)

enum class TournamentMode {
    Internal,
    External,
    Mini
}
