//
//  PlanningSettingsView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 07/04/2024.
//

import SwiftUI
import LeStorage

struct PlanningSettingsView: View {
    @EnvironmentObject var dataStore: DataStore
    @Bindable var tournament: Tournament
    @Bindable var matchScheduler: MatchScheduler
    
    @State private var groupStageChunkCount: Int
    @State private var isScheduling: Bool = false
    @State private var schedulingDone: Bool = false
    @State private var showOptions: Bool = false
    @State private var issueFound: Bool = false
    @State private var parallelType: Bool = false
    
    init(tournament: Tournament) {
        self.tournament = tournament
        if let matchScheduler = tournament.matchScheduler() {
            self.matchScheduler = matchScheduler
            if matchScheduler.groupStageChunkCount != nil {
                _parallelType = .init(wrappedValue: true)
                _groupStageChunkCount = State(wrappedValue: matchScheduler.groupStageChunkCount!)
            } else {
                _groupStageChunkCount = State(wrappedValue: tournament.getGroupStageChunkValue())
            }
        } else {
            self.matchScheduler = MatchScheduler(tournament: tournament.id)
            self._groupStageChunkCount = State(wrappedValue: tournament.getGroupStageChunkValue())
        }
    }
    
    var body: some View {
        List {
            SubscriptionInfoView()

            Section {
                DatePicker(selection: $tournament.startDate) {
                    Text(tournament.startDate.formatted(.dateTime.weekday(.wide)).capitalized)
                }
                LabeledContent {
                    StepperView(count: $tournament.dayDuration, minimum: 1)
                } label: {
                    Text("Durée")
                    Text("\(tournament.dayDuration) jour" + tournament.dayDuration.pluralSuffix)
                }

                TournamentFieldsManagerView(localizedStringKey: "Terrains maximum", count: $tournament.courtCount)
                
                if let event = tournament.eventObject() {
                    NavigationLink {
                        CourtAvailabilitySettingsView(event: event)
                            .environment(tournament)
                    } label: {
                        Text("Préciser la disponibilité des terrains")
                    }
                }
            } footer: {
                if let club = tournament.club() {
                    if tournament.courtCount < club.courtCount {
                        let plural = tournament.courtCount.pluralSuffix
                        let verb = tournament.courtCount > 1 ? "seront" : "sera"
                        Text("En réduisant les terrains maximum, seul\(plural) le\(plural) \(tournament.courtCount) premier\(plural) terrain\(plural) \(verb) utilisé\(plural)") + Text(", par contre, si vous augmentez le nombre de terrains, vous pourrez plutôt préciser quel terrain n'est pas disponible.")
                    } else if tournament.courtCount > club.courtCount {
                        let isCreatedByUser = club.hasBeenCreated(by: Store.main.userId)
                        Button {
                            do {
                                club.courtCount = tournament.courtCount
                                try dataStore.clubs.addOrUpdate(instance: club)
                            } catch {
                                Logger.error(error)
                            }
                        } label: {
                            if isCreatedByUser {
                                Text("Vous avez indiqué plus de terrains dans ce tournoi que dans le club.")
                                + Text("Mettre à jour le club ?").underline().foregroundStyle(.master)
                            } else {
                                Label("Vous avez indiqué plus de terrains dans ce tournoi que dans le club.", systemImage: "exclamationmark.triangle.fill").foregroundStyle(.logoRed)
                            }
                        }
                        .buttonStyle(.plain)
                        .disabled(isCreatedByUser == false)
                    }
                }
            }
            
            if issueFound {
                Text("Padel Club n'a pas réussi à définir un horaire pour tous les matchs de ce tournoi, à cause de la programmation d'autres épreuves ou de l'indisponibilité des terrains.")
                    .foregroundStyle(.logoRed)
            }

            Section {
                NavigationLink {
                    _optionsView()
                } label: {
                    Text("Voir les options avancées")
                }
            }
            
            let allMatches = tournament.allMatches()
            let allGroupStages = tournament.groupStages()
            let allRounds = tournament.allRounds()
            let matchesWithDate = allMatches.filter({ $0.startDate != nil })
            let groupStagesWithDate = allGroupStages.filter({ $0.startDate != nil })
            let roundsWithDate = allRounds.filter({ $0.startDate != nil })
            if matchesWithDate.isEmpty == false || groupStagesWithDate.isEmpty == false || roundsWithDate.isEmpty == false {
                Section {
                    RowButtonView("Supprimer les horaires des matches", role: .destructive) {
                        do {
                            allMatches.forEach({
                                $0.startDate = nil
                                $0.confirmed = false
                            })
                            try dataStore.matches.addOrUpdate(contentOfs: allMatches)
                        } catch {
                            Logger.error(error)
                        }
                    }
                } footer: {
                    Text("Garde les horaires définis pour les poules et les manches.")
                }

                Section {
                    RowButtonView("Supprimer tous les horaires", role: .destructive) {
                        do {
                            allMatches.forEach({ 
                                $0.startDate = nil
                                $0.confirmed = false
                            })
                            try dataStore.matches.addOrUpdate(contentOfs: allMatches)
                            
                            allGroupStages.forEach({ $0.startDate = nil })
                            try dataStore.groupStages.addOrUpdate(contentOfs: allGroupStages)
                            
                            allRounds.forEach({ $0.startDate = nil })
                            try dataStore.rounds.addOrUpdate(contentOfs: allRounds)
                        } catch {
                            Logger.error(error)
                        }
                    }
                }
            }
            
            Section {
                if groupStagesWithDate.isEmpty == false {
                    Text("Des dates de démarrages ont été indiqué pour les poules et seront prises en compte.")
                }
                if roundsWithDate.isEmpty == false {
                    Text("Des dates de démarrages ont été indiqué pour les manches et seront prises en compte.")
                }
                RowButtonView("Horaire intelligent", role: .destructive) {
                    await MainActor.run {
                        issueFound = false
                        schedulingDone = false
                    }
                    self.issueFound = await _setupSchedule()
                    await MainActor.run {
                        _save()
                        schedulingDone = true
                    }
                }
            } footer: {
                Text("Padel Club programmera tous les matchs de votre tournoi en fonction de différents paramètres, ") + Text("tout en tenant compte des horaires que vous avez fixé.").underline()
            }
        }
        .headerProminence(.increased)
        .onAppear {
            do {
                try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler)
            } catch {
                Logger.error(error)
            }
        }
        .overlay(alignment: .bottom) {
            if schedulingDone {
                if issueFound {
                    Label("Horaires mis à jour", systemImage: "xmark.circle.fill")
                        .toastFormatted()
                        .deferredRendering(for: .seconds(2))
                } else {
                    Label("Horaires mis à jour", systemImage: "checkmark.circle.fill")
                        .toastFormatted()
                        .deferredRendering(for: .seconds(2))
                }
            }
        }
        .onChange(of: tournament.startDate) {
            _save()
        }
        .onChange(of: tournament.courtCount) {
            _save()
        }
        .onChange(of: tournament.dayDuration) {
            _save()
        }
    }
    
    @ViewBuilder
    private func _optionsView() -> some View {
        List {
            if tournament.groupStageCount > 0 {
                Section {
                    Picker(selection: $parallelType) {
                        Text("Auto.").tag(false)
                        Text("Manuel").tag(true)
                    } label: {
                        Text("Poules en parallèle")
                        let value = tournament.getGroupStageChunkValue()
                        if parallelType == false, value > 1 {
                            Text("\(value.formatted()) poules commenceront en parallèle")
                        }
                    }
                    .onChange(of: parallelType) {
                        if parallelType {
                            groupStageChunkCount = tournament.getGroupStageChunkValue()
                        } else {
                            matchScheduler.groupStageChunkCount = nil
                        }
                    }
                    
                    if parallelType {
                        TournamentFieldsManagerView(localizedStringKey: "Poule en parallèle", count: $groupStageChunkCount, max: tournament.groupStageCount)
                            .onChange(of: groupStageChunkCount) {
                                matchScheduler.groupStageChunkCount = groupStageChunkCount
                            }
                    }
                } footer: {
                    Text("Vous pouvez indiquer le nombre de poule démarrant en même temps.")
                }
            }

            Section {
                Toggle(isOn: $matchScheduler.overrideCourtsUnavailability) {
                    Text("Ne pas tenir compte des autres épreuves")
                }

                Toggle(isOn: $matchScheduler.randomizeCourts) {
                    Text("Distribuer les terrains au hasard")
                }
                
                Toggle(isOn: $matchScheduler.shouldHandleUpperRoundSlice) {
                    Text("Équilibrer les matchs d'une manche sur plusieurs tours")
                }
                
                Toggle(isOn: $matchScheduler.shouldEndRoundBeforeStartingNext) {
                    Text("Finir une manche, classement inclus avant de continuer")
                }
            }
            
            Section {
                Toggle(isOn: $matchScheduler.accountUpperBracketBreakTime) {
                    Text("Tenir compte des pauses")
                    Text("Tableau")
                }
                
                Toggle(isOn: $matchScheduler.accountLoserBracketBreakTime) {
                    Text("Tenir compte des pauses")
                    Text("Classement")
                }
            }
            
            Section {
                Toggle(isOn: $matchScheduler.rotationDifferenceIsImportant) {
                    Text("Forcer un créneau supplémentaire entre 2 phases")
                }
                
                LabeledContent {
                    StepperView(count: $matchScheduler.upperBracketRotationDifference, minimum: 0, maximum: 2)
                } label: {
                    Text("Tableau")
                }
                .disabled(matchScheduler.rotationDifferenceIsImportant == false)
                
                LabeledContent {
                    StepperView(count: $matchScheduler.loserBracketRotationDifference, minimum: 0, maximum: 2)
                } label: {
                    Text("Classement")
                }
                .disabled(matchScheduler.rotationDifferenceIsImportant == false)
            }
            
            Section {
                LabeledContent {
                    StepperView(count: $matchScheduler.timeDifferenceLimit, step: 5)
                } label: {
                    Text("Optimisation des créneaux")
                    Text("Si libre plus de \(matchScheduler.timeDifferenceLimit) minutes")
                }
            }

        }
        .navigationTitle("Options avancées")
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
    }
    
    private func _setupSchedule() async -> Bool {
        return matchScheduler.updateSchedule(tournament: tournament)
    }
    
    private func _save() {
        do {
            try dataStore.matchSchedulers.addOrUpdate(instance: matchScheduler)
            try dataStore.tournaments.addOrUpdate(instance: tournament)
        } catch {
            Logger.error(error)
        }
    }
}

//#Preview {
//    PlanningSettingsView(tournament: Tournament.mock())
//}
