//
//  TableStructureView.swift
//  Padel Tournament
//
//  Created by Razmig Sarkissian on 04/10/2023.
//

import SwiftUI
import LeStorage

struct TableStructureView: View {
    @Environment(Tournament.self) private var tournament: Tournament
    @EnvironmentObject private var dataStore: DataStore
    @Environment(\.dismiss) var dismiss
    @State private var presentRefreshStructureWarning: Bool = false
    @State private var teamCount: Int = 0
    @State private var groupStageCount: Int = 0
    @State private var teamsPerGroupStage: Int = 0
    @State private var qualifiedPerGroupStage: Int = 0
    @State private var groupStageAdditionalQualified: Int = 0
    @State private var updatedElements: Set<StructureElement> = Set()
    @FocusState private var stepperFieldIsFocused: Bool

    var qualifiedFromGroupStage: Int {
        groupStageCount * qualifiedPerGroupStage
    }
    
    var teamsFromGroupStages: Int {
        groupStageCount * teamsPerGroupStage
    }
    
    var maxMoreQualified: Int {
        if teamsPerGroupStage - qualifiedPerGroupStage > 1 {
            return groupStageCount
        } else if teamsPerGroupStage - qualifiedPerGroupStage == 1 {
            return groupStageCount - 1
        } else {
            return 0
        }
    }
    
    var moreQualifiedLabel: String {
        if groupStageAdditionalQualified == 0 { return "Aucun" }
        return (groupStageAdditionalQualified > 1 ? "les \(groupStageAdditionalQualified)" : "le") + " meilleur\(groupStageAdditionalQualified.pluralSuffix) " + (qualifiedPerGroupStage + 1).ordinalFormatted()
    }
    
    var maxGroupStages: Int {
        teamCount / max(1, teamsPerGroupStage)
    }

    @ViewBuilder
    var body: some View {
        List {
            Section {
                LabeledContent {
                    StepperView(count: $teamCount, minimum: 4, maximum: 128)
                } label: {
                    Text("Nombre d'équipes")
                }
                LabeledContent {
                    StepperView(count: $groupStageCount, minimum: 0, maximum: maxGroupStages)
                } label: {
                    Text("Nombre de poules")
                }
            }
            
            if groupStageCount > 0 {
                if (teamCount / groupStageCount) > 1 {
                    Section {
                        LabeledContent {
                            StepperView(count: $teamsPerGroupStage, minimum: 2, maximum: (teamCount / groupStageCount))
                        } label: {
                            Text("Équipes par poule")
                        }
                        
                        LabeledContent {
                            StepperView(count: $qualifiedPerGroupStage, minimum: 1, maximum: (teamsPerGroupStage-1))
                        } label: {
                            Text("Qualifiés par poule")
                        }
                        
                        if qualifiedPerGroupStage < teamsPerGroupStage - 1 {
                            LabeledContent {
                                StepperView(count: $groupStageAdditionalQualified, minimum: 0, maximum: maxMoreQualified)
                            } label: {
                                Text("Qualifiés supplémentaires")
                                Text(moreQualifiedLabel)
                            }
                            .onChange(of: groupStageAdditionalQualified) {
                                if groupStageAdditionalQualified == groupStageCount {
                                    qualifiedPerGroupStage += 1
                                    groupStageAdditionalQualified -= groupStageCount
                                }
                            }
                        }
                        
                        if groupStageCount > 0 && teamsPerGroupStage > 0 {
                            LabeledContent {
                                let mp = teamsPerGroupStage * (teamsPerGroupStage - 1) / 2
                                Text(mp.formatted())
                            } label: {
                                Text("Matchs à jouer par poule")
                            }
                        }
                    }
                } else {
                    ContentUnavailableView("Erreur", systemImage: "divide.circle.fill", description: Text("Il y n'y a pas assez d'équipe pour ce nombre de poule."))
                }
            }
            
            Section {
                let tf = max(teamCount - teamsFromGroupStages + qualifiedFromGroupStage + (groupStageCount > 0 ? groupStageAdditionalQualified : 0), 0)
                if groupStageCount > 0 {
                    LabeledContent {
                        Text(teamsFromGroupStages.formatted())
                    } label: {
                        Text("Équipes en poule")
                    }
                    LabeledContent {
                        Text((qualifiedFromGroupStage + (groupStageCount > 0 ? groupStageAdditionalQualified : 0)).formatted())
                    } label: {
                        Text("Équipes qualifiées de poule")
                    }
                }
                LabeledContent {
                    let tsPure = max(teamCount - groupStageCount * teamsPerGroupStage, 0)
                    Text(tsPure.formatted())
                } label: {
                    Text("Nombre de têtes de série")
                }
                LabeledContent {
                    Text(tf.formatted())
                } label: {
                    Text("Équipes en tableau final")
                }
            }
            
            Section {
                RowButtonView("Sauver sans reconstuire l'existant") {
                    _saveWithoutRebuild()
                }
            }
                
            Section {
                RowButtonView("Reconstruire les poules", role:.destructive) {
                    _save(rebuildEverything: false)
                }
            }
            
            Section {
                RowButtonView("Tout refaire", role: .destructive) {
                    _save(rebuildEverything: true)
                }
            }
        }
        .focused($stepperFieldIsFocused)
        .onChange(of: stepperFieldIsFocused) {
            if stepperFieldIsFocused {
                DispatchQueue.main.async {
                    UIApplication.shared.sendAction(#selector(UIResponder.selectAll(_:)), to: nil, from: nil, for: nil)
                }
            }
        }
        .toolbarBackground(.visible, for: .navigationBar)
        .onAppear {
            teamCount = tournament.teamCount
            groupStageCount = tournament.groupStageCount
            teamsPerGroupStage = tournament.teamsPerGroupStage
            qualifiedPerGroupStage = tournament.qualifiedPerGroupStage
            groupStageAdditionalQualified = tournament.groupStageAdditionalQualified
        }
        .onChange(of: teamCount) {
            if teamCount != tournament.teamCount {
                updatedElements.insert(.teamCount)
            } else {
                updatedElements.remove(.teamCount)
            }
        }
        .onChange(of: groupStageCount) {
            if groupStageCount != tournament.groupStageCount {
                updatedElements.insert(.groupStageCount)
            } else {
                updatedElements.remove(.groupStageCount)
            }
        }
        .onChange(of: teamsPerGroupStage) {
            if teamsPerGroupStage != tournament.teamsPerGroupStage {
                updatedElements.insert(.teamsPerGroupStage)
            } else {
                updatedElements.remove(.teamsPerGroupStage)
            }        }
        .onChange(of: qualifiedPerGroupStage) {
            if qualifiedPerGroupStage != tournament.qualifiedPerGroupStage {
                updatedElements.insert(.qualifiedPerGroupStage)
            } else {
                updatedElements.remove(.qualifiedPerGroupStage)
            }        }
        .onChange(of: groupStageAdditionalQualified) {
            if groupStageAdditionalQualified != tournament.groupStageAdditionalQualified {
                updatedElements.insert(.groupStageAdditionalQualified)
            } else {
                updatedElements.remove(.groupStageAdditionalQualified)
            }        }
        .toolbar {
            ToolbarItem(placement: .keyboard) {
                Button("Confirmer") {
                    stepperFieldIsFocused = false
                    _verifyValueIntegrity()
                }
            }
            ToolbarItem(placement: .confirmationAction) {
                if tournament.state() == .initial {
                    ButtonValidateView {
                        _save(rebuildEverything: true)
                    }
                } else {
                    let requirements = Set(updatedElements.compactMap { $0.requiresRebuilding })
                    ButtonValidateView(role: .destructive) {
                        if requirements.isEmpty {
                            _save(rebuildEverything: false)
                        } else {
                            presentRefreshStructureWarning = true
                        }
                    }
                    .confirmationDialog("Refaire la structure", isPresented: $presentRefreshStructureWarning, actions: {
                        Button("Sauver sans reconstuire l'existant") {
                            _saveWithoutRebuild()
                        }
                        
                        Button("Reconstruire les poules") {
                            _save(rebuildEverything: false)
                        }
                        
                        Button("Tout refaire", role: .destructive) {
                            _save(rebuildEverything: true)
                        }
                    }, message: {
                        ForEach(Array(requirements)) { requirement in
                            Text(requirement.rebuildingRequirementMessage)
                        }
                    })
                }
            }
        }
        .navigationTitle("Structure")
        .navigationBarTitleDisplayMode(.inline)
    }

    
    private func _saveWithoutRebuild() {
        tournament.teamCount = teamCount
        tournament.groupStageCount = groupStageCount
        tournament.teamsPerGroupStage = teamsPerGroupStage
        tournament.qualifiedPerGroupStage = qualifiedPerGroupStage
        tournament.groupStageAdditionalQualified = groupStageAdditionalQualified
        do {
            try dataStore.tournaments.addOrUpdate(instance: tournament)
        } catch {
            Logger.error(error)
        }
        dismiss()
    }
        
    private func _save(rebuildEverything: Bool = false) {
        _verifyValueIntegrity()
        
        do {
            let requirements = Set(updatedElements.compactMap { $0.requiresRebuilding })

            tournament.teamCount = teamCount
            tournament.groupStageCount = groupStageCount
            tournament.teamsPerGroupStage = teamsPerGroupStage
            tournament.qualifiedPerGroupStage = qualifiedPerGroupStage
            tournament.groupStageAdditionalQualified = groupStageAdditionalQualified

            if (rebuildEverything == false && requirements.contains(.all)) || rebuildEverything {
                tournament.deleteAndBuildEverything()
            } else if (rebuildEverything == false && requirements.contains(.groupStage)) {
                tournament.deleteGroupStages()
                tournament.buildGroupStages()
            }

            try dataStore.tournaments.addOrUpdate(instance: tournament)

            dismiss()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
    
    private func _verifyValueIntegrity() {
        if teamCount > 128 {
            teamCount = 128
        }
        
        if groupStageCount > maxGroupStages {
            groupStageCount = maxGroupStages
        }
        
        if teamCount < 4 {
            teamCount = 4
        }
        
        if groupStageCount < 0 {
            groupStageCount = 0
        }

        if groupStageCount > 0 {
            if teamsPerGroupStage > (teamCount / groupStageCount) {
                teamsPerGroupStage = (teamCount / groupStageCount)
            }

            if qualifiedPerGroupStage > (teamsPerGroupStage-1) {
                qualifiedPerGroupStage = (teamsPerGroupStage-1)
            }
            
            if groupStageAdditionalQualified > maxMoreQualified {
                groupStageAdditionalQualified = maxMoreQualified
            }

            if teamsPerGroupStage < 2 {
                teamsPerGroupStage = 2
            }
            
            if qualifiedPerGroupStage < 1 {
                qualifiedPerGroupStage = 1
            }
            
            if groupStageAdditionalQualified < 0 {
                groupStageAdditionalQualified = 0
            }
        }

    }
}

extension TableStructureView {
    
    enum StructureElement: Int, Identifiable {
        case teamCount
        case groupStageCount
        case teamsPerGroupStage
        case qualifiedPerGroupStage
        case groupStageAdditionalQualified
        var id: Int { self.rawValue }
        
        var requiresRebuilding: RebuildingRequirement? {
            switch self {
            case .teamCount:
                return .all
            case .groupStageCount:
                return .groupStage
            case .teamsPerGroupStage:
                return .groupStage
            case .qualifiedPerGroupStage:
                return nil
            case .groupStageAdditionalQualified:
                return nil
            }
        }
    }
    
    enum RebuildingRequirement: Int, Identifiable {
        case groupStage
        case all
        
        var id: Int { self.rawValue }

        var rebuildingRequirementMessage: String {
            switch self {
            case .groupStage:
                return "Si vous le souhaitez, seulement les poules seront refaites. Le tableau ne sera pas modifié."
            case .all:
                return "Tous les matchs seront re-générés. La position des têtes de série sera remise à zéro et les poules seront reconstruites."
            }
        }
    }

}

//#Preview {
//    NavigationStack {
//        TableStructureView()
//            .environment(Tournament.mock())
//            .environmentObject(DataStore.shared)
//    }
//}
