//
//  TournamentRankView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 30/04/2024.
//

import SwiftUI
import LeStorage

struct TournamentRankView: View {
    @Environment(Tournament.self) var tournament: Tournament
    @EnvironmentObject var dataStore: DataStore
    @Environment(\.editMode) private var editMode

    @State private var rankings: [Int: [TeamRegistration]] = [:]
    @State private var calculating = false
    @State private var selectedTeam: TeamRegistration?
    
    var tournamentStore: TournamentStore {
        return self.tournament.tournamentStore
    }
    
    var isEditingTeam: Binding<Bool> {
        Binding {
            selectedTeam != nil
        } set: { value in
        }
    }
    
    var body: some View {
        List {
            @Bindable var tournament = tournament
            let rankingsCalculated = tournament.selectedSortedTeams().anySatisfy({ $0.finalRanking != nil })
            if editMode?.wrappedValue.isEditing == false {
                Section {
                    let all = tournament.allMatches()
                    let runningMatches = tournament.runningMatches(all)
                    let matchesLeft = tournament.readyMatches(all)

                    MatchListView(section: "Matchs restant", matches: matchesLeft, hideWhenEmpty: false, isExpanded: false)
                    MatchListView(section: "Matchs en cours", matches: runningMatches, hideWhenEmpty: false, isExpanded: false)
                    
                    Toggle(isOn: $tournament.hidePointsEarned) {
                        Text("Masquer les points gagnés")
                    }
                    .onChange(of: tournament.hidePointsEarned) {
                        do {
                            try dataStore.tournaments.addOrUpdate(instance: tournament)
                        } catch {
                            Logger.error(error)
                        }
                    }
                    
                    Toggle(isOn: $tournament.publishRankings) {
                        Text("Publier sur Padel Club")
                        if let url = tournament.shareURL(.rankings) {
                            Link(destination: url) {
                                Text("Accéder à la page")
                            }
                        }
                    }
                    .onChange(of: tournament.publishRankings) {
                        do {
                            try dataStore.tournaments.addOrUpdate(instance: tournament)
                        } catch {
                            Logger.error(error)
                        }
                    }
                }
            }

            if (editMode?.wrappedValue.isEditing == true || rankingsCalculated == false) && calculating == false {
                Section {
                    RowButtonView(rankingsCalculated ? "Re-calculer le classement" : "Calculer", role: .destructive) {
                        await _calculateRankings()
                    }
                } footer: {
                    if rankingsCalculated {
                        Text("Vos éditions seront perdus.")
                    }
                }

                if rankingsCalculated {
                    Section {
                        RowButtonView("Supprimer le classement", role: .destructive) {
                            tournament.unsortedTeams().forEach { team in
                                team.finalRanking = nil
                                team.pointsEarned = nil
                            }
                            _save()
                        }
                    }
                }
            }

            
            let teamsRanked = tournament.teamsRanked()
            if calculating == false && rankingsCalculated && teamsRanked.isEmpty == false {
                Section {
                    ForEach(teamsRanked) { team in
                        if let key = team.finalRanking {
                            TeamRankCellView(team: team, key: key)
                        }
                    }
                }
            }
        }
        .alert("Position", isPresented: isEditingTeam) {
            if let selectedTeam {
                @Bindable var team = selectedTeam
                TextField("Position", value: $team.finalRanking, format: .number)
                    .keyboardType(.numberPad)
                    .multilineTextAlignment(.trailing)
                    .frame(maxWidth: .infinity)
                
                Button("Valider") {
                    selectedTeam.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: selectedTeam.finalRanking! - 1, count: tournament.teamCount)
                    do {
                        try self.tournamentStore.teamRegistrations.addOrUpdate(instance: selectedTeam)
                    } catch {
                        Logger.error(error)
                    }

                    self.selectedTeam = nil
                }

                Button("Annuler", role: .cancel) {
                    self.selectedTeam = nil
                }
            }
        }
        .overlay(content: {
            if calculating {
                ProgressView()
            }
        })
        .onAppear {
            let rankingPublished = tournament.selectedSortedTeams().anySatisfy({ $0.finalRanking != nil })
            if rankingPublished == false {
                Task {
                    await _calculateRankings()
                }
            }
        }
        .navigationTitle("Classement")
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                EditButton()
            }
        }
    }
    
    struct TeamRankCellView: View {
        @Environment(\.editMode) private var editMode
        @Environment(Tournament.self) var tournament: Tournament
        @State private var isEditingTeam: Bool = false
        @Bindable var team: TeamRegistration
        @State var key: Int
        
        var body: some View {
            VStack(spacing: 0) {
                if editMode?.wrappedValue.isEditing == true {
                    if key > 1 {
                        FooterButtonView("monter") {
                            key -= 1
                            team.finalRanking = key
                            team.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: key - 1, count: tournament.teamCount)
                            do {
                                try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
                            } catch {
                                Logger.error(error)
                            }
                        }
                    }
                }
                
                Button {
                    isEditingTeam = true
                } label: {
                    HStack {
                        VStack(alignment: .trailing) {
                            VStack(alignment: .trailing, spacing: -8.0) {
                                ZStack(alignment: .trailing) {
                                    Text(tournament.teamCount.formatted()).hidden()
                                    Text(key.formatted())
                                }
                                .monospacedDigit()
                                .font(.largeTitle)
                                .fontWeight(.bold)
                                Text(key.ordinalFormattedSuffix()).font(.caption)
                            }
                            if let index = tournament.indexOf(team: team) {
                                let rankingDifference = index - (key - 1)
                                if rankingDifference > 0 {
                                    HStack(spacing: 0.0) {
                                        Text(rankingDifference.formatted(.number.sign(strategy: .always())))
                                            .monospacedDigit()
                                        Image(systemName: "arrowtriangle.up.fill")
                                            .imageScale(.small)
                                    }
                                    .foregroundColor(.green)
                                } else if rankingDifference < 0 {
                                    HStack(spacing: 0.0) {
                                        Text(rankingDifference.formatted(.number.sign(strategy: .always())))
                                            .monospacedDigit()
                                        Image(systemName: "arrowtriangle.down.fill")
                                            .imageScale(.small)
                                    }
                                    .foregroundColor(.logoRed)
                                } else {
                                    Text("--")
                                }
                            }
                        }
                        
                        
                        Divider()
                        
                        VStack(alignment: .leading) {
                            if let name = team.name {
                                Text(name).foregroundStyle(.secondary)
                            }
                            
                            ForEach(team.players()) { player in
                                VStack(alignment: .leading, spacing: -4.0) {
                                    Text(player.playerLabel()).bold()
                                    HStack(alignment: .firstTextBaseline, spacing: 0.0) {
                                        Text(player.rankLabel())
                                        if let rank = player.getRank() {
                                            Text(rank.ordinalFormattedSuffix())
                                                .font(.caption)
                                        }
                                    }
                                }
                            }
                        }
                        if tournament.isAnimation() == false && key > 0 {
                            Spacer()
                            VStack(alignment: .trailing) {
                                HStack(alignment: .lastTextBaseline, spacing: 0.0) {
                                    Text(tournament.tournamentLevel.points(for: key - 1, count: tournament.teamCount).formatted(.number.sign(strategy: .always())))
                                    Text("pts").font(.caption)
                                }
                            }
                        }
                    }
                    .frame(maxWidth: .infinity)
                }
                .contentShape(Rectangle())
                .buttonStyle(.plain)

                if editMode?.wrappedValue.isEditing == true {
                    FooterButtonView("descendre") {
                        key += 1
                        team.finalRanking = key
                        team.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: key - 1, count: tournament.teamCount)

                        do {
                            try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
                        } catch {
                            Logger.error(error)
                        }
                    }
                }
            }
            .alert("Position", isPresented: $isEditingTeam) {
                TextField("Position", value: $team.finalRanking, format: .number)
                    .keyboardType(.numberPad)
                    .multilineTextAlignment(.trailing)
                    .frame(maxWidth: .infinity)
                
                Button("Valider") {
                    team.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: key - 1, count: tournament.teamCount)
                    do {
                        try self.tournament.tournamentStore.teamRegistrations.addOrUpdate(instance: team)
                    } catch {
                        Logger.error(error)
                    }
                    
                    isEditingTeam = false
                }

                Button("Annuler", role: .cancel) {
                    isEditingTeam = false
                }
            }
        }
    }
        
    private func _calculateRankings() async {
        await MainActor.run {
            calculating = true
        }

        let finalRanks = await tournament.finalRanking()
        finalRanks.keys.sorted().forEach { rank in
            if let rankedTeamIds = finalRanks[rank] {
                let teams: [TeamRegistration] = rankedTeamIds.compactMap { self.tournamentStore.teamRegistrations.findById($0) }
                self.rankings[rank] = teams
            }
        }

        await MainActor.run {
            rankings.keys.sorted().forEach { rank in
                if let rankedTeams = rankings[rank] {
                    rankedTeams.forEach { team in
                        team.finalRanking = rank
                        team.pointsEarned = tournament.isAnimation() ? nil : tournament.tournamentLevel.points(for: rank - 1, count: tournament.teamCount)
                    }
                }
            }
            _save()
            
            calculating = false
        }
    }
    
    private func _save() {
        do {
            try self.tournamentStore.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
        } catch {
            Logger.error(error)
        }
    }
}

//#Preview {
//    TournamentRankView()
//}
