//
//  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?
    @State private var assimilationSelection: TournamentLevel?
    
    var tournamentStore: TournamentStore? {
        return self.tournament.tournamentStore
    }
    
    var isEditingTeam: Binding<Bool> {
        Binding {
            selectedTeam != nil
        } set: { value in
        }
    }
    
    var hideRankings: Binding<Bool> {
        Binding {
            tournament.publishRankings == false
        } set: { value in
            tournament.publishRankings = !value
        }
    }
    
    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)
                        }
                    }
                    
                    if tournament.level == .championship {
                        Picker(selection: $assimilationSelection) {
                            Text("Aucune").tag(nil as TournamentLevel?)
                            ForEach(TournamentLevel.assimilationAllCases) {
                                Text($0.localizedLevelLabel()).tag($0)
                            }
                        } label: {
                            Text("Assimilation")
                        }
                    }
                    
                    //affiche l'onglet sur le site, car sur le broadcast c'est dispo automatiquement de toute façon
                    Toggle(isOn: $tournament.publishRankings) {
                        if calculating {
                            ProgressView("Calcul en cours")
                        } else {
                            Text("Publier sur Padel Club")
                        }
                    }
                    .disabled(calculating)
                    
                    Toggle(isOn: $tournament.disableRankingFederalRuling) {
                        Text("Désactiver la règle fédéral")
                        Text("Dernier de poule ≠ derner du tournoi")
                    }
                    .onChange(of: tournament.disableRankingFederalRuling) {
                        dataStore.tournaments.addOrUpdate(instance: tournament)
                        Task {
                            await _calculateRankings()
                        }
                    }
                    .disabled(calculating)

                } footer: {
                    if let url = tournament.shareURL(.rankings) {
                        Link(destination: url) {
                            Text("Voir les classements sur Padel Club")
                        }
                    }
                }
            }

            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
                            }
                            
                            tournament.publishRankings = false
                            _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)
                        }
                    }
                }
            }
        }
        .id(calculating)
        .onChange(of: tournament.publishRankings) {
            do {
                try dataStore.tournaments.addOrUpdate(instance: tournament)
            } catch {
                Logger.error(error)
            }
        }
        .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
                }
            }
        }
        .onAppear {
            let rankingPublished = tournament.selectedSortedTeams().anySatisfy({ $0.finalRanking != nil })
            if rankingPublished == false {
                Task {
                    await _calculateRankings()
                    tournament.publishRankings = true
                }
            }
        }
        .navigationTitle("Classement")
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                EditButton()
            }
        }
    }
    
    struct TeamRankCellView: View {
        @EnvironmentObject var dataStore: DataStore
        @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 {
                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) {
                                ZStack {
                                    HStack(spacing: 0.0) {
                                        Text(tournament.teamCount.formatted(.number.sign(strategy: .always())))
                                            .monospacedDigit()
                                        Image(systemName: "arrowtriangle.down.fill")
                                            .imageScale(.small)
                                    }
                                    .opacity(0)
                                    
                                    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 teamName = team.name, teamName.isEmpty == false {
                                Text(teamName).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)
                                        }
                                    }
                                }
                            }
                        }

                        Spacer()
                        if tournament.isAnimation() == false && key > 0 {
                            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
        }

        self.rankings.removeAll()
        let finalRanks = await tournament.finalRanking()
        self.rankings = await tournament.setRankings(assimilationLevel: assimilationSelection, finalRanks: finalRanks)
        calculating = false
    }
    
    private func _save() {
        do {
            try self.tournamentStore?.teamRegistrations.addOrUpdate(contentOfs: tournament.unsortedTeams())
        } catch {
            Logger.error(error)
        }
    }
}

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