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.ClubLeagueItem
import de.trainingstagebuch.app.repository.ClubLeaguesResult
import de.trainingstagebuch.app.repository.ClubTeamActionResult
import de.trainingstagebuch.app.repository.ClubTeamItem
import de.trainingstagebuch.app.repository.ClubTeamsResult
import de.trainingstagebuch.app.repository.MyTischtennisActionResult
import de.trainingstagebuch.app.repository.SchedulerJobsOverview
import de.trainingstagebuch.app.repository.SchedulerJobsResult
import de.trainingstagebuch.app.repository.TeamDocumentItem
import de.trainingstagebuch.app.repository.TeamDocumentParseResult
import de.trainingstagebuch.app.repository.TeamDocumentUploadResult
import de.trainingstagebuch.app.repository.TeamDocumentsResult
import de.trainingstagebuch.app.repository.TeamPlayerStatItem
import de.trainingstagebuch.app.repository.TeamPlayerStatsResult
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.delay
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
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonPrimitive

class TeamManagementViewModel(application: Application) : AndroidViewModel(application) {
    private val authService = AppServices.authService
    private val membersService = AppServices.membersService
    private val service = AppServices.teamManagementService

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

    init {
        loadAll()
    }

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

            val leagues = when (val result = service.loadLeagues(clubId = clubId, seasonId = _state.value.selectedSeasonId)) {
                is ClubLeaguesResult.Success -> result.items
                is ClubLeaguesResult.Error -> {
                    showError(result.message, result.code)
                    return@launch
                }
            }

            val teams = when (val result = service.loadTeams(clubId = clubId, seasonId = _state.value.selectedSeasonId)) {
                is ClubTeamsResult.Success -> result.items
                is ClubTeamsResult.Error -> {
                    showError(result.message, result.code)
                    return@launch
                }
            }

            val scheduler = when (val result = service.loadSchedulerJobs(clubId = clubId)) {
                is SchedulerJobsResult.Success -> result.data
                is SchedulerJobsResult.Error -> SchedulerJobsOverview()
            }

            _state.update {
                val selectedId = it.selectedTeamId ?: teams.firstOrNull()?.id
                it.copy(
                    loading = false,
                    teams = teams,
                    leagues = leagues,
                    selectedTeamId = selectedId,
                    schedulerJobs = scheduler
                )
            }
            selectedTeam()?.let { loadTeamDetails(it.id) }
        }
    }

    fun setSeasonId(seasonId: String?) {
        _state.update { it.copy(selectedSeasonId = seasonId?.trim()?.ifBlank { null }) }
        loadAll()
    }

    fun selectTeam(teamId: String) {
        _state.update { it.copy(selectedTeamId = teamId) }
        loadTeamDetails(teamId)
    }

    fun saveTeam(name: String, leagueId: String?) {
        viewModelScope.launch {
            val clubId = resolveClubId() ?: return@launch
            val teamId = _state.value.selectedTeamId
            val seasonId = _state.value.selectedSeasonId
            if (seasonId.isNullOrBlank()) {
                _state.update { it.copy(errorMessage = UiText(R.string.team_management_season_required)) }
                return@launch
            }
            if (name.trim().isBlank()) {
                _state.update { it.copy(errorMessage = UiText(R.string.team_management_name_required)) }
                return@launch
            }

            val result = if (teamId.isNullOrBlank()) {
                service.createTeam(clubId = clubId, name = name.trim(), leagueId = leagueId, seasonId = seasonId)
            } else {
                service.updateTeam(teamId = teamId, name = name.trim(), leagueId = leagueId, seasonId = seasonId)
            }

            when (result) {
                is ClubTeamActionResult.Success -> {
                    _state.update {
                        it.copy(
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.team_management_saved)
                            )
                        )
                    }
                    loadAll()
                    result.teamId?.let { createdId -> selectTeam(createdId) }
                }

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

    fun deleteSelectedTeam() {
        val teamId = _state.value.selectedTeamId ?: return
        viewModelScope.launch {
            when (val result = service.deleteTeam(teamId)) {
                is ClubTeamActionResult.Success -> {
                    _state.update {
                        it.copy(
                            selectedTeamId = null,
                            documents = emptyList(),
                            playerStats = emptyList(),
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.team_management_deleted)
                            )
                        )
                    }
                    loadAll()
                }

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

    fun parseDocument(documentId: String) {
        val team = selectedTeam() ?: return
        val leagueId = team.leagueId ?: return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true) }
            when (val result = service.parseTeamDocument(documentId = documentId, leagueId = leagueId)) {
                is TeamDocumentParseResult.Success -> {
                    _state.update {
                        it.copy(
                            actionLoading = false,
                            successMessage = UiText(R.string.team_management_document_parsed)
                        )
                    }
                    loadTeamDetails(team.id)
                }

                is TeamDocumentParseResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(result.message, result.code)
                }
            }
        }
    }

    fun uploadDocument(documentType: String, fileName: String, bytes: ByteArray) {
        val team = selectedTeam() ?: return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true) }
            when (
                val result = service.uploadTeamDocument(
                    clubTeamId = team.id,
                    documentType = documentType,
                    fileName = fileName,
                    bytes = bytes
                )
            ) {
                is TeamDocumentUploadResult.Success -> {
                    _state.update {
                        it.copy(
                            actionLoading = false,
                            successMessage = if (result.message.isNullOrBlank()) {
                                UiText(R.string.team_management_document_uploaded)
                            } else {
                                ViewModelStateUtils.dynamicOrFallback(result.message)
                            }
                        )
                    }
                    loadTeamDetails(team.id)
                }

                is TeamDocumentUploadResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(result.message, result.code)
                }
            }
        }
    }

    fun parseMyTischtennisUrl(url: String) {
        if (url.trim().isBlank()) return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true, urlActionMessage = null, errorMessage = null) }
            when (val result = service.parseMyTischtennisUrl(url.trim())) {
                is MyTischtennisActionResult.Success -> {
                    val data = result.payload?.get("data") as? JsonObject
                    val urlType = data?.get("urlType")?.jsonPrimitive?.contentOrNull?.trim()
                    _state.update {
                        it.copy(
                            actionLoading = false,
                            parsedUrl = url.trim(),
                            parsedUrlType = urlType,
                            urlActionMessage = UiText(R.string.team_management_url_parsed)
                        )
                    }
                }

                is MyTischtennisActionResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(result.message, result.code)
                }
            }
        }
    }

    fun configureMyTischtennisForSelectedTeam() {
        val team = selectedTeam() ?: return
        val url = _state.value.parsedUrl ?: return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true) }
            when (val result = service.configureMyTischtennisTeam(url = url, clubTeamId = team.id)) {
                is MyTischtennisActionResult.Success -> {
                    _state.update {
                        it.copy(
                            actionLoading = false,
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.team_management_mytischtennis_configured)
                            )
                        )
                    }
                    loadAll()
                }

                is MyTischtennisActionResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(result.message, result.code)
                }
            }
        }
    }

    fun configureMyTischtennisLeague() {
        val url = _state.value.parsedUrl ?: return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true) }
            when (val result = service.configureMyTischtennisLeague(url = url)) {
                is MyTischtennisActionResult.Success -> {
                    _state.update {
                        it.copy(
                            actionLoading = false,
                            successMessage = ViewModelStateUtils.dynamicOrFallback(
                                result.message,
                                UiText(R.string.team_management_league_configured)
                            )
                        )
                    }
                    loadAll()
                }

                is MyTischtennisActionResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(result.message, result.code)
                }
            }
        }
    }

    fun fetchTeamData() {
        val team = selectedTeam() ?: return
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true, urlActionMessage = null) }
            when (val start = service.startFetchTeamDataJob(clubTeamId = team.id)) {
                is MyTischtennisActionResult.Success -> {
                    val jobId = start.payload?.get("jobId")?.jsonPrimitive?.contentOrNull?.trim().orEmpty()
                    if (jobId.isBlank()) {
                        _state.update { it.copy(actionLoading = false, errorMessage = UiText(R.string.error_unknown)) }
                        return@launch
                    }
                    pollJob(jobId)
                }

                is MyTischtennisActionResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(start.message, start.code)
                }
            }
        }
    }

    private suspend fun pollJob(jobId: String) {
        repeat(40) {
            delay(2000)
            when (val poll = service.getFetchTeamDataJob(jobId)) {
                is MyTischtennisActionResult.Success -> {
                    val job = poll.payload?.get("job") as? JsonObject
                    val status = job?.get("status")?.jsonPrimitive?.contentOrNull?.trim()
                    if (status == "completed") {
                        _state.update {
                            it.copy(
                                actionLoading = false,
                                successMessage = UiText(R.string.team_management_fetch_completed)
                            )
                        }
                        loadAll()
                        return
                    }
                    if (status == "failed") {
                        _state.update {
                            it.copy(
                                actionLoading = false,
                                errorMessage = UiText(R.string.team_management_fetch_failed)
                            )
                        }
                        return
                    }
                }

                is MyTischtennisActionResult.Error -> {
                    _state.update { it.copy(actionLoading = false) }
                    showError(poll.message, poll.code)
                    return
                }
            }
        }
        _state.update { it.copy(actionLoading = false, errorMessage = UiText(R.string.team_management_fetch_timeout)) }
    }

    private fun loadTeamDetails(teamId: String) {
        viewModelScope.launch {
            _state.update { it.copy(actionLoading = true) }
            when (val documentsResult = service.loadTeamDocuments(teamId = teamId)) {
                is TeamDocumentsResult.Success -> {
                    _state.update { it.copy(documents = documentsResult.items) }
                }

                is TeamDocumentsResult.Error -> {
                    showError(documentsResult.message, documentsResult.code)
                }
            }

            val team = selectedTeam()
            val clubId = resolveClubId() ?: return@launch
            if (team?.leagueId != null) {
                when (
                    val statsResult = service.loadPlayerStats(
                        clubId = clubId,
                        leagueId = team.leagueId,
                        seasonId = _state.value.selectedSeasonId
                    )
                ) {
                    is TeamPlayerStatsResult.Success -> {
                        val membersMap = when (val membersResult = membersService.loadMembers(clubId)) {
                            is de.trainingstagebuch.app.repository.MembersResult.Success -> membersResult.members.associateBy { it.id }
                            else -> emptyMap()
                        }
                        _state.update {
                            it.copy(
                                playerStats = statsResult.items,
                                memberRatings = membersMap.mapValues { (_, member) -> member.displayName }
                            )
                        }
                    }

                    is TeamPlayerStatsResult.Error -> Unit
                }
            } else {
                _state.update { it.copy(playerStats = emptyList()) }
            }
            _state.update { it.copy(actionLoading = false) }
        }
    }

    private fun selectedTeam(): ClubTeamItem? {
        val selected = _state.value.selectedTeamId ?: return null
        return _state.value.teams.firstOrNull { it.id == selected }
    }

    private suspend fun resolveClubId(): String? {
        val clubId = authService.session.first().currentClub?.trim().orEmpty()
        if (clubId.isBlank()) {
            _state.update {
                it.copy(
                    loading = false,
                    actionLoading = 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,
                actionLoading = false,
                errorMessage = ViewModelStateUtils.normalizeUiText(
                    ErrorMessageFormatter.dynamicWithOptionalCode(message, code)
                )
            )
        }
    }
}

data class TeamManagementUiState(
    val loading: Boolean = false,
    val actionLoading: Boolean = false,
    val selectedSeasonId: String? = null,
    val teams: List<ClubTeamItem> = emptyList(),
    val leagues: List<ClubLeagueItem> = emptyList(),
    val selectedTeamId: String? = null,
    val documents: List<TeamDocumentItem> = emptyList(),
    val playerStats: List<TeamPlayerStatItem> = emptyList(),
    val memberRatings: Map<String, String> = emptyMap(),
    val schedulerJobs: SchedulerJobsOverview = SchedulerJobsOverview(),
    val parsedUrl: String? = null,
    val parsedUrlType: String? = null,
    val urlActionMessage: UiText? = null,
    val errorMessage: UiText? = null,
    val successMessage: UiText? = null
)
