//
//  GroupStagesView.swift
//  Padel Tournament
//
//  Created by Razmig Sarkissian on 11/12/2023.
//

import SwiftUI
import LeStorage

struct GroupStagesView: View {
    @State var tournament: Tournament
    @State private var selectedDestination: GroupStageDestination?
    @EnvironmentObject var dataStore: DataStore
    let step: Int

    enum GroupStageDestination: Selectable, Identifiable, Equatable {
        static func == (lhs: GroupStagesView.GroupStageDestination, rhs: GroupStagesView.GroupStageDestination) -> Bool {
            lhs.id == rhs.id
        }
        
        case all(Tournament)
        case loserBracket(Round)
        case groupStage(GroupStage)
        
        var id: String {
            switch self {
            case .all:
                return "all-group-stage"
            case .loserBracket(let loserBracket):
                return loserBracket.id
            case .groupStage(let groupStage):
                return groupStage.id
            }
        }
        
        func selectionLabel(index: Int) -> String {
            switch self {
            case .all:
                return "Tout"
            case .loserBracket:
                return "Classement"
            case .groupStage(let groupStage):
                return groupStage.groupStageTitle()
            }
        }
        
        func badgeValue() -> Int? {
            switch self {
            case .all:
                return nil
            case .loserBracket(let loserBracket):
                return loserBracket.badgeValue()
            case .groupStage(let groupStage):
                return groupStage.badgeValue()
            }
        }
        
        func badgeValueColor() -> Color? {
            return nil
        }
        
        func badgeImage() -> Badge? {
            switch self {
            case .all(let tournament):
                if tournament.groupStageAdditionalQualified > 0 && tournament.moreQualifiedToDraw() > 0 && tournament.missingQualifiedFromGroupStages().isEmpty == false {
                    return .custom(systemName: "exclamationmark.circle.fill", color: .logoBackground)
                } else {
                    return nil
                }
            case .loserBracket(let loserBracket):
                if loserBracket._matches().isEmpty { return nil }
                return loserBracket.badgeImage()
            case .groupStage(let groupStage):
                return groupStage.badgeImage()
            }
        }
    }
    
    var allMatches: [Match] {
        tournament.groupStagesMatches(atStep: step)
    }
        
    init(tournament: Tournament, step: Int = 0) {
        self.tournament = tournament
        self.step = step
        if tournament.shouldVerifyGroupStage {
            _selectedDestination = State(wrappedValue: nil)
        } else if tournament.unsortedTeams().filter({ $0.groupStagePosition != nil }).isEmpty {
            _selectedDestination = State(wrappedValue: nil)
        } else {
            let gs = tournament.getActiveGroupStage(atStep: step)
            if let gs {
                _selectedDestination = State(wrappedValue: .groupStage(gs))
            }
        }
    }
    
    func allDestinations() -> [GroupStageDestination] {
        var allDestinations : [GroupStageDestination] = [.all(tournament)]
        let groupStageDestinations : [GroupStageDestination] = tournament.groupStages(atStep: step).map { GroupStageDestination.groupStage($0) }
        if let loserBracket = tournament.groupStageLoserBracket() {
            allDestinations.insert(.loserBracket(loserBracket), at: 0)
        }
        allDestinations.append(contentsOf: groupStageDestinations)
        return allDestinations
    }
    
    func sortedTeams(missingQualifiedFromGroupStages: [TeamRegistration]) -> [GroupStage.TeamGroupStageScore] {
        let sortedTeams = missingQualifiedFromGroupStages.compactMap({ team in
            team.groupStageObject()?.computedScore(forTeam: team)
        }).sorted { (lhs, rhs) in
            let predicates: [GroupStage.TeamScoreAreInIncreasingOrder] = [
                { $0.wins < $1.wins },
                { $0.setDifference < $1.setDifference },
                { $0.gameDifference < $1.gameDifference},
            ]
            
            for predicate in predicates {
                if !predicate(lhs, rhs) && !predicate(rhs, lhs) {
                    continue
                }
                
                return predicate(lhs, rhs)
            }
            
            return false
        }
        return sortedTeams
    }
    
    func _sortedAdditionnalTeams(missingQualifiedFromGroupStages: [TeamRegistration]) -> some View {
        Section {
            let teamGroupStageScores = self.sortedTeams(missingQualifiedFromGroupStages: missingQualifiedFromGroupStages).reversed()
            ForEach(teamGroupStageScores, id: \.team.id) { teamGroupStageScore in
                let team = teamGroupStageScore.team
                let groupStage = team.groupStageObject()!
                let groupStagePosition = team.groupStagePosition!

                NavigationLink {
                    GroupStageTeamView(groupStage: groupStage, team: team)
                        .environment(self.tournament)
                } label: {
                    HStack {
                        VStack(alignment: .leading) {
                            if let teamName = team.name, teamName.isEmpty == false {
                                Text(teamName).foregroundStyle(.secondary).font(.footnote)
                            }
                            ForEach(team.players()) { player in
                                Text(player.playerLabel()).lineLimit(1)
                            }
                        }
                        Spacer()
                        if let score = groupStage.scoreLabel(forGroupStagePosition: groupStagePosition, score: teamGroupStageScore) {
                            VStack(alignment: .trailing) {
                                HStack(spacing: 0.0) {
                                    Text(score.wins)
                                    Text("/")
                                    Text(score.losses)
                                }.font(.headline).monospacedDigit()
                                if let setsDifference = score.setsDifference {
                                    HStack(spacing: 4.0) {
                                        Text(setsDifference)
                                    }.font(.footnote)
                                }
                                if let gamesDifference = score.gamesDifference {
                                    HStack(spacing: 4.0) {
                                        Text(gamesDifference)
                                    }.font(.footnote)
                                }
                            }
                        }
                    }
                }
            }
        } header: {
            let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())"
            Text("Meilleurs \(name) de poule")
        }

    }

    var body: some View {
        VStack(spacing: 0) {
            GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: allDestinations(), nilDestinationIsValid: true)
            switch selectedDestination {
            case .all:
                let finishedMatches = Tournament.finishedMatches(allMatches, limit: nil)

                List {
                    if tournament.groupStageAdditionalQualified > 0 {
                        let missingQualifiedFromGroupStages = tournament.missingQualifiedFromGroupStages()
                        let name = "\((tournament.qualifiedPerGroupStage + 1).ordinalFormatted())"
                        Section {
                            NavigationLink {
                                SpinDrawView(drawees: ["Qualification d'un \(name) de poule"], segments: missingQualifiedFromGroupStages) { results in
                                    results.forEach { drawResult in
                                        missingQualifiedFromGroupStages[drawResult.drawIndex].qualified = true
                                        do {
                                            try self.tournament.tournamentStore?.teamRegistrations.addOrUpdate(instance: missingQualifiedFromGroupStages[drawResult.drawIndex])
                                        } catch {
                                            Logger.error(error)
                                        }
                                    }
                                }
                            } label: {
                                Text("Qualifier un \(name) de poule par tirage au sort")
                            }
                            .disabled(tournament.moreQualifiedToDraw() == 0 || missingQualifiedFromGroupStages.isEmpty)
                        } header: {
                            Text("Tirage au sort d'un \(name) de poule")
                        } footer: {
                            if tournament.moreQualifiedToDraw() == 0 {
                                Text("Aucune équipe supplémentaire à qualifier. Vous pouvez en rajouter en modifier le paramètre dans structure.")
                            } else if missingQualifiedFromGroupStages.isEmpty {
                                Text("Aucune équipe supplémentaire à tirer au sort. Attendez la fin des poules.")
                            }
                        }
                        
                        _sortedAdditionnalTeams(missingQualifiedFromGroupStages: missingQualifiedFromGroupStages)
                    }

                    let runningMatches = Tournament.runningMatches(allMatches)
                    Section {
                        
                        MatchListView(section: "en cours", matches: runningMatches, isExpanded: false)
                    }
                    Section {
                        
                        MatchListView(section: "prêt à démarrer", matches: Tournament.availableToStart(allMatches, in: runningMatches), isExpanded: false)

                    }
                    
                    Section {
                        
                        MatchListView(section: "à lancer", matches: Tournament.readyMatches(allMatches), isExpanded: false)
                    }
                    
                    Section {
                        
                        MatchListView(section: "terminés", matches: finishedMatches, isExpanded: false)
                    }
                }
                .matchViewStyle(.standardStyle)
                .navigationTitle("Toutes les poules")
            case .groupStage(let groupStage):
                GroupStageView(groupStage: groupStage).id(groupStage.id)
            case .loserBracket(let loserBracket):
                LoserBracketFromGroupStageView(loserBracket: loserBracket).id(loserBracket.id)
            case nil:
                GroupStagesSettingsView(step: step)
                    .navigationTitle("Réglages")
            }
        }
        .environment(tournament)
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
    }
}
