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.ScheduleActionResult
import de.trainingstagebuch.app.repository.ScheduleLeagueTableResult
import de.trainingstagebuch.app.repository.ScheduleLeagueTableRow
import de.trainingstagebuch.app.repository.ScheduleMatchItem
import de.trainingstagebuch.app.repository.ScheduleMatchesResult
import de.trainingstagebuch.app.repository.ScheduleTeamItem
import de.trainingstagebuch.app.repository.ScheduleTeamsResult
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 ScheduleViewModel(application: Application) : AndroidViewModel(application) {
    private val authService = AppServices.authService
    private val scheduleService = AppServices.scheduleService

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

    init {
        observeSocketEvents()
        loadInitial()
    }

    fun retry() = loadInitial()

    fun selectTeam(teamId: String?) {
        _state.update { it.copy(selectedTeamId = teamId, selectedTab = ScheduleTab.Schedule) }
        reloadMatchesAndTable()
    }

    fun selectTab(tab: ScheduleTab) {
        _state.update { it.copy(selectedTab = tab) }
    }

    fun openPlayerDialog(matchId: String) {
        val match = _state.value.matches.firstOrNull { it.id == matchId } ?: return
        _state.update { it.copy(playerDialogMatchId = matchId, playerDialogLoading = true, playerDialogError = null) }
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) {
                _state.update {
                    it.copy(
                        playerDialogLoading = false,
                        playerDialogError = UiText(R.string.error_no_current_club)
                    )
                }
                return@launch
            }
            when (val result = scheduleService.loadMembers(clubId)) {
                is MembersResult.Success -> {
                    val members = result.members.filter { it.active }
                    _state.update {
                        it.copy(
                            playerDialogLoading = false,
                            playerSelections = members.map { member ->
                                PlayerSelectionItem(
                                    member = member,
                                    isReady = match.playersReady.contains(member.id),
                                    isPlanned = match.playersPlanned.contains(member.id),
                                    hasPlayed = match.playersPlayed.contains(member.id)
                                )
                            }
                        )
                    }
                }

                is MembersResult.Error -> {
                    _state.update {
                        it.copy(
                            playerDialogLoading = false,
                            playerDialogError = ViewModelStateUtils.normalizeUiText(
                                ErrorMessageFormatter.dynamicWithOptionalCode(result.message, null)
                            )
                        )
                    }
                }
            }
        }
    }

    fun closePlayerDialog() {
        _state.update {
            it.copy(
                playerDialogMatchId = null,
                playerDialogLoading = false,
                playerDialogError = null,
                playerSelections = emptyList()
            )
        }
    }

    fun toggleReady(memberId: String) {
        _state.update { state ->
            state.copy(
                playerSelections = state.playerSelections.map { item ->
                    if (item.member.id == memberId) item.copy(isReady = !item.isReady) else item
                }
            )
        }
    }

    fun togglePlanned(memberId: String) {
        _state.update { state ->
            state.copy(
                playerSelections = state.playerSelections.map { item ->
                    if (item.member.id == memberId) item.copy(isPlanned = !item.isPlanned) else item
                }
            )
        }
    }

    fun togglePlayed(memberId: String) {
        _state.update { state ->
            state.copy(
                playerSelections = state.playerSelections.map { item ->
                    if (item.member.id == memberId) item.copy(hasPlayed = !item.hasPlayed) else item
                }
            )
        }
    }

    fun savePlayerSelection() {
        val matchId = _state.value.playerDialogMatchId ?: return
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) {
                _state.update { it.copy(playerDialogError = UiText(R.string.error_no_current_club)) }
                return@launch
            }
            val ready = _state.value.playerSelections.filter { it.isReady }.map { it.member.id }
            val planned = _state.value.playerSelections.filter { it.isPlanned }.map { it.member.id }
            val played = _state.value.playerSelections.filter { it.hasPlayed }.map { it.member.id }
            when (val result = scheduleService.saveMatchPlayers(matchId, clubId, ready, planned, played)) {
                is ScheduleActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(result.message, UiText(R.string.schedule_players_saved))
                        )
                    }
                    closePlayerDialog()
                    reloadMatchesAndTable()
                }

                is ScheduleActionResult.Error -> {
                    _state.update {
                        it.copy(
                            playerDialogError = ViewModelStateUtils.normalizeUiText(
                                ErrorMessageFormatter.dynamicWithOptionalCode(result.message, result.code)
                            )
                        )
                    }
                }
            }
        }
    }

    private fun loadInitial() {
        viewModelScope.launch {
            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@launch
            }
            _state.update { it.copy(loading = true, errorMessage = null) }
            when (val teamResult = scheduleService.loadTeams(clubId)) {
                is ScheduleTeamsResult.Success -> {
                    val firstTeamId = teamResult.teams.firstOrNull()?.id
                    _state.update {
                        it.copy(
                            loading = false,
                            teams = teamResult.teams,
                            selectedTeamId = it.selectedTeamId ?: firstTeamId
                        )
                    }
                    reloadMatchesAndTable()
                }

                is ScheduleTeamsResult.Error -> {
                    _state.update {
                        it.copy(
                            loading = false,
                            errorMessage = ViewModelStateUtils.normalizeUiText(
                                ErrorMessageFormatter.dynamicWithOptionalCode(teamResult.message, teamResult.code)
                            )
                        )
                    }
                }
            }
        }
    }

    private fun reloadMatchesAndTable() {
        viewModelScope.launch {
            val clubId = authService.session.first().currentClub?.trim().orEmpty()
            if (clubId.isBlank()) return@launch
            val selectedTeam = _state.value.teams.firstOrNull { it.id == _state.value.selectedTeamId }
            val leagueId = selectedTeam?.leagueId

            _state.update { it.copy(loading = true, errorMessage = null) }
            when (val matchesResult = scheduleService.loadMatches(clubId, leagueId = leagueId)) {
                is ScheduleMatchesResult.Success -> {
                    _state.update { it.copy(matches = matchesResult.matches) }
                }

                is ScheduleMatchesResult.Error -> {
                    _state.update {
                        it.copy(
                            loading = false,
                            errorMessage = ViewModelStateUtils.normalizeUiText(
                                ErrorMessageFormatter.dynamicWithOptionalCode(matchesResult.message, matchesResult.code)
                            )
                        )
                    }
                    return@launch
                }
            }
            if (!leagueId.isNullOrBlank()) {
                when (val tableResult = scheduleService.loadLeagueTable(clubId, leagueId)) {
                    is ScheduleLeagueTableResult.Success -> {
                        _state.update {
                            it.copy(
                                loading = false,
                                leagueTable = tableResult.rows
                            )
                        }
                    }

                    is ScheduleLeagueTableResult.Error -> {
                        _state.update {
                            it.copy(
                                loading = false,
                                errorMessage = ViewModelStateUtils.normalizeUiText(
                                    ErrorMessageFormatter.dynamicWithOptionalCode(tableResult.message, tableResult.code)
                                )
                            )
                        }
                    }
                }
            } else {
                _state.update { it.copy(loading = false, leagueTable = emptyList()) }
            }
        }
    }

    private fun observeSocketEvents() {
        viewModelScope.launch {
            scheduleService.socketEvents.collect { event ->
                when (event.type) {
                    DomainSocketEventType.ScheduleMatchUpdated,
                    DomainSocketEventType.ScheduleMatchReportSubmitted -> reloadMatchesAndTable()

                    else -> Unit
                }
            }
        }
    }
}

data class ScheduleUiState(
    val loading: Boolean = false,
    val teams: List<ScheduleTeamItem> = emptyList(),
    val selectedTeamId: String? = null,
    val selectedTab: ScheduleTab = ScheduleTab.Schedule,
    val matches: List<ScheduleMatchItem> = emptyList(),
    val leagueTable: List<ScheduleLeagueTableRow> = emptyList(),
    val playerDialogMatchId: String? = null,
    val playerDialogLoading: Boolean = false,
    val playerDialogError: UiText? = null,
    val playerSelections: List<PlayerSelectionItem> = emptyList(),
    val errorMessage: UiText? = null,
    val successMessage: UiText? = null
)

enum class ScheduleTab {
    Schedule,
    Table
}

data class PlayerSelectionItem(
    val member: MemberItem,
    val isReady: Boolean,
    val isPlanned: Boolean,
    val hasPlayed: Boolean
)
