//
//  RoundView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 30/03/2024.
//

import SwiftUI
import LeStorage
import TipKit

struct RoundView: View {
    
    @Environment(\.isEditingTournamentSeed) private var isEditingTournamentSeed
    @Environment(Tournament.self) var tournament: Tournament
    @EnvironmentObject var dataStore: DataStore
    @Environment(NavigationViewModel.self) private var navigation: NavigationViewModel
    
    @State private var selectedSeedGroup: SeedInterval?
    @State private var showPrintScreen: Bool = false
    @State private var hideNames: Bool = true
    
    var upperRound: UpperRound
    
    init(upperRound: UpperRound) {
        self.upperRound = upperRound
        let seeds = upperRound.round.seeds()
        SlideToDeleteSeedTip.seeds = seeds.count
        PrintTip.seeds = seeds.count
        BracketEditTip.matchesHidden = upperRound.round.getDisabledMatches().count
    }
    
    var tournamentStore: TournamentStore? {
        return self.tournament.tournamentStore
    }
    
    private var spaceLeft: [Match] {
        let displayableMatches: [Match] = self.upperRound.round.playedMatches()
        return displayableMatches.filter { match in
            match.teamScores.count == 1
        }.filter({ $0.isValidSpot() })
    }
    
    private var seedSpaceLeft: [Match] {
        let displayableMatches: [Match] = self.upperRound.round.playedMatches()
        return displayableMatches.filter { match in
            match.teamScores.count == 0
        }.filter({ $0.isValidSpot() })
    }
    
    private var availableSeedGroup: SeedInterval? {
        tournament.seedGroupAvailable(atRoundIndex: upperRound.round.index)
    }
    
    var showVisualDrawView: Binding<Bool> { Binding(
        get: { selectedSeedGroup != nil },
        set: {
            if $0 == false {
                selectedSeedGroup = nil
            }
        }
    )}
    
    var body: some View {
        List {
            let displayableMatches = upperRound.round.playedMatches().sorted(by: \.index)
            if displayableMatches.isEmpty {
                Section {
                    ContentUnavailableView("Aucun match dans cette manche", systemImage: "tennisball")
                }
            }
            
            let disabledMatchesCount = BracketEditTip.matchesHidden
            if disabledMatchesCount > 0 {
                let bracketTip = BracketEditTip(nextRoundName: upperRound.round.nextRound()?.roundTitle())
                TipView(bracketTip).tipStyle(tint: .green, asSection: true)
                
                let leftToPlay = (RoundRule.numberOfMatches(forRoundIndex: upperRound.round.index) - disabledMatchesCount)
                
                if upperRound.round.hasStarted() == false, leftToPlay >= 0 {
                    Section {
                        LabeledContent {
                            Text(leftToPlay.formatted())
                        } label: {
                            Text("Match\(leftToPlay.pluralSuffix) à jouer en \(upperRound.title)")
                        }
                    } footer: {
                        Text("\(disabledMatchesCount) match\(disabledMatchesCount.pluralSuffix) désactivé\(disabledMatchesCount.pluralSuffix) automatiquement")
                    }
                }
            }
            
            if isEditingTournamentSeed.wrappedValue == false {
                //(where: { $0.isDisabled() == false || isEditingTournamentSeed.wrappedValue })
                let printTip = PrintTip()
                TipView(printTip) { actions in
                    showPrintScreen = true
                }
                .tipStyle(tint: .master, asSection: true)
                
                if upperRound.round.index > 0 {
                    let correspondingLoserRoundTitle = upperRound.round.correspondingLoserRoundTitle()
                    Section {
                        NavigationLink {
                            LoserRoundsView(upperBracketRound: upperRound)
                                .environment(tournament)
                                .navigationTitle(correspondingLoserRoundTitle)
                        } label: {
                            LabeledContent {
                                let status = upperRound.status()
                                if status.0 == status.1 {
                                    if status.0 == 0 {
                                        Text("aucun match")
                                    } else {
                                        Image(systemName: "checkmark").foregroundStyle(.green)
                                    }
                                } else {
                                    Text("\(status.0) terminé\(status.0.pluralSuffix) sur \(status.1)")
                                }
                            } label: {
                                Text(correspondingLoserRoundTitle)
                            }
                        }
                    } header: {
                        Text("Match de classement")
                    }
                }
            } else {
                let isRoundValidForSeeding = tournament.isRoundValidForSeeding(roundIndex: upperRound.round.index)
                let availableSeeds = tournament.availableSeeds()
                let availableQualifiedTeams = tournament.availableQualifiedTeams()
                
                if availableSeeds.isEmpty == false, let availableSeedGroup {
                    _seedGroupSection(availableSeeds: availableSeeds, availableSeedGroup: availableSeedGroup)
                }
                
                if availableQualifiedTeams.isEmpty == false {
                    let qualifiedOnSeedSpot = (spaceLeft.isEmpty || tournament.seeds().isEmpty) ? true : false
                    let availableSeedSpot : [any SpinDrawable] = qualifiedOnSeedSpot ? (seedSpaceLeft + spaceLeft).flatMap({ $0.matchSpots() }).filter({ $0.match.team( $0.teamPosition) == nil }) : spaceLeft
                    Section {
                        DisclosureGroup {
                            ForEach(availableQualifiedTeams) { team in
                                NavigationLink {
                                    
                                    SpinDrawView(drawees: [team], segments: availableSeedSpot) { results in
                                        Task {
                                            results.forEach { drawResult in
                                                if let matchSpot : MatchSpot = availableSeedSpot[drawResult.drawIndex] as? MatchSpot {
                                                    team.setSeedPosition(inSpot: matchSpot.match, slot: matchSpot.teamPosition, opposingSeeding: false)
                                                } else if let matchSpot : Match = availableSeedSpot[drawResult.drawIndex] as? Match {
                                                    team.setSeedPosition(inSpot: matchSpot, slot: nil, opposingSeeding: true)
                                                }
                                            }
                                            
                                            _save(seeds: [team])
                                        }
                                    }
                                } label: {
                                    TeamRowView(team: team, displayCallDate: false)
                                }
                                .disabled(availableSeedSpot.isEmpty || isRoundValidForSeeding == false)
                            }
                        } label: {
                            Text("Qualifié\(availableQualifiedTeams.count.pluralSuffix) à placer").badge(availableQualifiedTeams.count)
                        }
                    } header: {
                        Text("Tirage au sort visuel d'un qualifié").font(.subheadline)
                    } footer: {
                        if availableSeedSpot.isEmpty || isRoundValidForSeeding == false {
                            Text("Aucune place disponible !")
                                .foregroundStyle(.red)
                        }
                    }
                }
                
                if availableSeeds.isEmpty == false {
                    let spots = (seedSpaceLeft.isEmpty == false) ? seedSpaceLeft : spaceLeft
                    let opposingSeeding = (seedSpaceLeft.isEmpty == false) ? false : true
                    _drawSection(availableSeeds: availableSeeds, spots: spots, opposingSeeding: opposingSeeding, isRoundValidForSeeding: isRoundValidForSeeding)
                }
            }
            
            if isEditingTournamentSeed.wrappedValue == true {
                let slideToDelete = SlideToDeleteSeedTip()
                TipView(slideToDelete).tipStyle(tint: .logoRed, asSection: true)
            }
            
            ForEach(displayableMatches) { match in
                let matchTitle = match.matchTitle(.short, inMatches: displayableMatches)
                Section {
                    MatchRowView(match: match, title: matchTitle)
                        .matchViewStyle(.sectionedStandardStyle)
                } header: {
                    HStack {
                        Text(upperRound.round.roundTitle(.wide))
                        if upperRound.round.index > 0 {
                            Text(matchTitle)
                        } else {
                            let tournamentTeamCount = tournament.teamCount
                            if let seedIntervalPointRange = upperRound.round.seedInterval()?.pointsRange(tournamentLevel: tournament.tournamentLevel, teamsCount: tournamentTeamCount) {
                                Spacer()
                                Text(seedIntervalPointRange)
                                    .font(.caption)
                            }
                        }
                        
#if DEBUG
                        Spacer()
                        
                        Text(match.index.formatted() + " " + match.teamScores.count.formatted())
#endif
                    }
                } footer: {
                    if isEditingTournamentSeed.wrappedValue == true && match.followingMatch()?.disabled == true {
                        FooterButtonView("Désactiver", role: .destructive) {
                            match.disableMatch()
                            do {
                                try tournamentStore?.matches.addOrUpdate(instance: match)
                            } catch {
                                Logger.error(error)
                            }
                        }
                    }
                }
            }
            
            if upperRound.round.index == 0, tournament.hasEnded() {
                NavigationLink(value: Screen.rankings) {
                    LabeledContent {
                        if tournament.publishRankings == false {
                            Image(systemName: "exclamationmark.circle.fill")
                                .foregroundStyle(.logoYellow)
                        } else {
                            Image(systemName: "checkmark")
                                .foregroundStyle(.green)
                        }
                    } label: {
                        Text("Classement final")
                        if tournament.publishRankings == false {
                            Text("Vérifiez le classement avant de publier").foregroundStyle(.logoRed)
                        }
                    }
                }
            }
        }
        .navigationDestination(isPresented: $showPrintScreen) {
            PrintSettingsView(tournament: tournament)
        }
        .fullScreenCover(isPresented: showVisualDrawView) {
            if let availableSeedGroup = selectedSeedGroup {
                let seeds = _seeds(availableSeedGroup: availableSeedGroup)
                let availableSeedSpot = _availableSeedSpot(availableSeedGroup: availableSeedGroup)
                NavigationStack {
                    SpinDrawView(drawees: seeds, segments: availableSeedSpot, autoMode: true, hideNames: hideNames) { draws in
                        Task {
                            draws.forEach { drawResult in
                                seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: opposingSeeding)
                            }
                            _save(seeds: seeds)
                        }
                    }
                }
            }
        }
        .headerProminence(.increased)
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button(isEditingTournamentSeed.wrappedValue == true ? "Valider" : "Modifier") {
                    if isEditingTournamentSeed.wrappedValue == true {
                        _save()
                        isEditingTournamentSeed.wrappedValue = false
                    } else {
                        isEditingTournamentSeed.wrappedValue = true
                    }
                }
            }
        }
    }
    
    private func _seeds(availableSeedGroup: SeedInterval) -> [TeamRegistration] {
        tournament.seeds(inSeedGroup: availableSeedGroup)
    }
    
    var opposingSeeding: Bool {
        seedSpaceLeft.isEmpty ? true : false
    }
    
    private func _warnGroupWillCloseRound(availableSeedGroup: SeedInterval) -> Bool {
        opposingSeeding
        && seedSpaceLeft.count <= availableSeedGroup.count
        && tournament.rounds().count - 1 > upperRound.round.index
    }
    
    private func _availableSeedSpot(availableSeedGroup: SeedInterval) -> [Match] {
        let spots = opposingSeeding ? spaceLeft : seedSpaceLeft
        if availableSeedGroup == SeedInterval(first: 3, last: 4), spots.count == 6 {
            var array = [Match]()
            array.append(spots[1])
            array.append(spots[4])
            return array
        } else {
            return spots
        }
    }
    
    
    private func _save(seeds: [TeamRegistration]) {
        do {
            try self.tournamentStore?.teamRegistrations.addOrUpdate(contentOfs: seeds)
        } catch {
            Logger.error(error)
        }
        
        if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
            self.isEditingTournamentSeed.wrappedValue = false
        }
        
        _refreshNames()
    }
    
    private func _save() {
        if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
            self.isEditingTournamentSeed.wrappedValue = false
        }
        _refreshNames()
    }
    
    private func _refreshNames() {
        DispatchQueue.global(qos: .background).async {
            //todo should be done server side
            let rounds = tournament.rounds()
            var matchesToUpdate: [Match] = [Match]()
            rounds.forEach { round in
                let matches = round.playedMatches().filter({ $0.name == nil })
                matches.forEach { match in
                    match.setMatchName(Match.setServerTitle(upperRound: round, matchIndex: match.indexInRound(in: matches)))
                }
                matchesToUpdate.append(contentsOf: matches)
            }
            
            let loserMatches = self.upperRound.loserMatches()
            loserMatches.forEach { match in
                match.setMatchName(match.roundTitle())
            }
            
            do {
                try tournament.tournamentStore?.matches.addOrUpdate(contentOfs: matchesToUpdate + loserMatches)
            } catch {
                Logger.error(error)
            }
        }
    }
    
    private func _drawSection(availableSeeds: [TeamRegistration], spots: [Match], opposingSeeding: Bool, isRoundValidForSeeding: Bool) -> some View {
        Section {
            DisclosureGroup {
                ForEach(availableSeeds) { team in
                    NavigationLink {
                        SpinDrawView(drawees: [team], segments: spots) { results in
                            Task {
                                results.forEach { drawResult in
                                    team.setSeedPosition(inSpot: spots[drawResult.drawIndex], slot: nil, opposingSeeding: opposingSeeding)
                                }
                                
                                _save(seeds: [team])
                            }
                        }
                    } label: {
                        TeamRowView(team: team, displayCallDate: false)
                    }
                    .disabled(spots.isEmpty || isRoundValidForSeeding == false)
                }
            } label: {
                Text("Tête\(availableSeeds.count.pluralSuffix) de série à placer").badge(availableSeeds.count)
            }
        } header: {
            Text("Tirage au sort visuel d'une tête de série").font(.subheadline)
        } footer: {
            if spots.isEmpty || isRoundValidForSeeding == false {
                Text("Aucune place disponible ! Ajouter une manche via les réglages du tableau.")
                    .foregroundStyle(.red)
            }
        }
    }
    
    private func _seedGroupSection(availableSeeds: [TeamRegistration], availableSeedGroup: SeedInterval) -> some View {
        Group {
            let warnGroupWillCloseRound = _warnGroupWillCloseRound(availableSeedGroup: availableSeedGroup)
            Section {
                RowButtonView("Placer \(availableSeedGroup.localizedInterval())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : ""), role: warnGroupWillCloseRound ? .destructive : nil, confirmationMessage: warnGroupWillCloseRound ? "Attention, tous vos matchs du tour précédent seront désactivés" : nil)  {
                    Task {
                        tournament.setSeeds(inRoundIndex: upperRound.round.index, inSeedGroup: availableSeedGroup)
                        _save(seeds: availableSeeds)
                    }
                }
//                if upperRound.round.index == 3, availableSeedGroup.first == 5, availableSeedGroup.last == 8, availableSeeds.count > 1, let half = availableSeedGroup.chunks()?.first {
//                    FooterButtonView("ou placer \(half.localizedInterval())" + ((half.isFixed() == false) ? " au hasard" : ""))  {
//                        Task {
//                            tournament.setSeeds(inRoundIndex: upperRound.round.index, inSeedGroup: half)
//                            _save(seeds: availableSeeds)
//                        }
//                    }
//                }
            } footer: {
                if availableSeedGroup.isFixed() == false {
                    Text("Le tirage au sort ne sera pas visuel. Toutes les équipes de ce chapeau seront tirées.")
                }
            }

            if (availableSeedGroup.isFixed() == false) {
                Section {
                    Toggle(isOn: $hideNames) {
                        Text("Masquer les noms")
                        if hideNames {
                            Text("Réalise un tirage des positions.")
                        }
                    }
                    RowButtonView("Tirage au sort \(availableSeedGroup.localizedInterval()) visuel", role: warnGroupWillCloseRound ? .destructive : nil, confirmationMessage: warnGroupWillCloseRound ? "Attention, tous vos matchs du tour précédent seront désactivés" : nil) {
                        self.selectedSeedGroup = availableSeedGroup
                    }
//                    if upperRound.round.index == 3, availableSeedGroup.first == 5, availableSeedGroup.last == 8, availableSeeds.count > 1, let half = availableSeedGroup.chunks()?.first {
//                        FooterButtonView("ou tirage au sort \(half.localizedInterval()) visuel")  {
//                            self.selectedSeedGroup = half
//                        }
//                    }
                } footer: {
                    Text("Le tirage au sort sera visuel et automatique, n'hésitez pas à enregistrer une vidéo de votre écran. Toutes les équipes de ce chapeau seront tirées les unes après les autres.")
                }
            }
        }
    }
}
