//
//  TournamentLookUpView.swift
//  PadelClub
//
//  Created by razmig on 08/09/2024.
//

import SwiftUI
import CoreLocation
import CoreLocationUI

struct TournamentLookUpView: View {
    @EnvironmentObject var dataStore: DataStore
    @Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel
    @StateObject var locationManager = LocationManager()
    @Environment(\.dismiss) private var dismiss
    @FocusState private var isFocused: Bool

    @State private var searchField: String = ""
    @State var page: Int = 0
    @State var total: Int = 0
    @State private var showingSettingsAlert = false
    @State private var searching: Bool = false
    @State private var requestedToGetAllPages: Bool = false
    @State private var revealSearchParameters: Bool = true
    @State private var presentAlert: Bool = false
    @State private var confirmSearch: Bool = false
    @State private var locationRequested = false
    
    var tournaments: [FederalTournament] {
        federalDataViewModel.searchedFederalTournaments
    }
    
    var showLastError: Binding<Bool> {
        Binding {
            locationManager.lastError != nil
        } set: { value in
        }
    }
        
    var body: some View {
        List {
            searchParametersView
        }
        .alert(isPresented: showLastError, error: locationManager.lastError as? LocationManager.LocationError, actions: { 
            Button("Annuler", role: .cancel) {
                
            }
        })
        .confirmationDialog("Attention", isPresented: $confirmSearch, titleVisibility: .visible) {
            Button("Cherchez quand même") {
                requestedToGetAllPages = true
                runSearch()
            }
                        
            Button("Annuler", role: .cancel) {
                
            }
        } message: {
            Text("Aucune ville n'a été indiqué, il est préférable de se localiser ou d'indiquer une ville pour réduire le nombre de résultat.")
        }
        .alert(isPresented: $showingSettingsAlert) {
            Alert(
                title: Text("Réglages"),
                message: Text("Pour trouver les clubs autour de vous, vous devez l'autorisation à Padel Club de récupérer votre position."),
                primaryButton: .default(Text("Ouvrir les réglages"), action: {
                    _openSettings()
                }),
                secondaryButton: .cancel()
            )
        }
        .alert("Attention", isPresented: $presentAlert, actions: {
            Button {
                presentAlert = false
                requestedToGetAllPages = true
                page += 1
                searching = true
                Task {
                    await getNewPage()
                    searching = false
                    dismiss()
                }
            } label: {
                Label("Tout voir", systemImage: "arrow.down.circle")
            }
            Button("Annuler") {
                revealSearchParameters = true
                presentAlert = false
            }
        }, message: {
            if dataStore.appSettings.city.isEmpty {
                Text("Il est préférable de se localiser ou d'indiquer une ville pour réduire le nombre de résultat.")
            } else {
                Text("Il y a beacoup de tournois pour cette requête, êtes-vous sûr de vouloir tout récupérer ? Sinon essayez d'affiner votre recherche.")
            }
        })
        .toolbarBackground(.visible, for: .bottomBar, .navigationBar)
        .navigationTitle("Chercher un tournoi")
        .navigationBarTitleDisplayMode(.inline)
        .onChange(of: locationManager.city) {
            if locationRequested, let newValue = locationManager.city {
                dataStore.appSettings.city = newValue
                locationRequested = false
            }
        }
        .toolbarTitleDisplayMode(.large)
        .toolbar {
            ToolbarItem(placement: .bottomBar) {
                if revealSearchParameters {
                    FooterButtonView("Lancer la recherche") {
                        if dataStore.appSettings.city.isEmpty {
                            confirmSearch = true
                        } else {
                            runSearch()
                        }
                    }
                    .disabled(searching)
                } else if searching {
                    HStack(spacing: 20) {
                        Spacer()
                        ProgressView()
                        if total > 0 {
                            let percent = Double(tournaments.count) / Double(total)
                            Text(percent.formatted(.percent.precision(.significantDigits(1...3))) + " en récupération de Tenup")
                                .font(.caption)
                        }
                        Spacer()
                    }
                }
            }
            ToolbarItem(placement: .topBarTrailing) {
                Menu {
#if DEBUG
                    if tournaments.isEmpty == false {
                        Section {
                            ShareLink(item: pastedTournaments) {
                                Label("Par texte", systemImage: "square.and.arrow.up")
                                    .labelStyle(.titleAndIcon)
                            }
                            ShareLink(item: japList) {
                                Label("JAP liste", systemImage: "square.and.arrow.up")
                                    .labelStyle(.titleAndIcon)
                            }
                        } header: {
                            Text("Partager les résultats")
                        }
                    }
                    Divider()
#endif

                    Button(role: .destructive) {
                        dataStore.appSettings.resetSearch()
                        locationManager.location = nil
                        locationManager.city = nil
                        revealSearchParameters = true
                        federalDataViewModel.searchedFederalTournaments = []
                        federalDataViewModel.searchAttemptCount = 0
                    } label: {
                        Text("Ré-initialiser la recherche")
                    }
                } label: {
                    Label("Options", systemImage: "ellipsis.circle")
                }
            }
        }
    }
    var pastedTournaments: String {
        tournaments.map { $0.shareMessage }.joined()
    }
    
    var japList: String {
        Set(tournaments.map { $0.japMessage }).joined(separator: "\n")
    }
    
    private var clubsFound: [String] {
        Set(tournaments.compactMap { $0.nomClub }).sorted()
    }

    private var liguesFound: [String] {
        Set(tournaments.compactMap { $0.nomLigue }).sorted()
    }

    private func runSearch() {
        dataStore.appSettingsStorage.write()
        revealSearchParameters = false
        total = 0
        page = 0
        federalDataViewModel.searchedFederalTournaments = []
        searching = true
        requestedToGetAllPages = false
        federalDataViewModel.searchAttemptCount += 1
        federalDataViewModel.dayPeriod = dataStore.appSettings.dayPeriod
        federalDataViewModel.dayDuration = dataStore.appSettings.dayDuration
        federalDataViewModel.levels = Set(levels)
        federalDataViewModel.categories = Set(categories)
        federalDataViewModel.ageCategories = Set(ages)
        federalDataViewModel.lastError = nil

        Task {
            await getNewPage()
            searching = false
            if tournaments.isEmpty == false && tournaments.count < total && total >= 200 && requestedToGetAllPages == false {
                presentAlert = true
            } else {
                dismiss()
            }
        }
    }

    private var distanceLimit: Measurement<UnitLength> {
        distanceLimit(distance: dataStore.appSettings.distance)
    }
    
    private func distanceLimit(distance: Double) -> Measurement<UnitLength> {
        Measurement(value: distance, unit: .kilometers)
    }
    
    private var categories: [TournamentCategory] {
        dataStore.appSettings.tournamentCategories.compactMap { TournamentCategory(rawValue: $0) }
    }

    private var levels: [TournamentLevel] {
        dataStore.appSettings.tournamentLevels.compactMap { TournamentLevel(rawValue: $0) }
    }
    
    private var ages: [FederalTournamentAge] {
        dataStore.appSettings.tournamentAges.compactMap { FederalTournamentAge(rawValue: $0) }
    }
    
    private var types: [FederalTournamentType] {
        dataStore.appSettings.tournamentTypes.compactMap { FederalTournamentType(rawValue: $0) }
    }
    
    func getNewPage() async {
        do {
            if NetworkFederalService.shared.formId.isEmpty {
                await getNewBuildForm()
            } else {
                let commands = try await NetworkFederalService.shared.getAllFederalTournaments(sortingOption: dataStore.appSettings.sortingOption, page: page, startDate: dataStore.appSettings.startDate, endDate: dataStore.appSettings.endDate, city: dataStore.appSettings.city, distance: dataStore.appSettings.distance, categories: categories, levels: levels, lat: locationManager.location?.coordinate.latitude.formatted(.number.locale(Locale(identifier: "us"))), lng: locationManager.location?.coordinate.longitude.formatted(.number.locale(Locale(identifier: "us"))), ages: ages, types: types, nationalCup: dataStore.appSettings.nationalCup)
                if commands.anySatisfy({ $0.command == "alert" }) {
                    federalDataViewModel.lastError = .maintenance
                }

                let resultCommand = commands.first(where: { $0.results != nil })
                
                if let newTournaments = resultCommand?.results?.items {
                    newTournaments.forEach { ft in
//                        let isValid = ft.tournaments.anySatisfy({ build in
//                            let ageValid = ages.isEmpty ? true : ages.contains(build.age)
//                            let levelValid = levels.isEmpty ? true : levels.contains(build.level)
//                            let categoryValid = categories.isEmpty ? true : categories.contains(build.category)
//                            return ageValid && levelValid && categoryValid
//                        })
                        if tournaments.contains(where: { $0.id == ft.id }) == false {
                            federalDataViewModel.searchedFederalTournaments.append(ft)
                        }
                    }
                }
                if let count = resultCommand?.results?.nb_results {
                    print("count", count, total, tournaments.count, page)
                    total = count
                    
                    if tournaments.count < count && page < total / 30 {
                        if total < 200 || requestedToGetAllPages {
                            page += 1
                            await getNewPage()
                        }
                    } else {
                        print("finished")
                    }
                } else {
                    print("total results not found")
                }
            }
        } catch {
            print("getNewPage", error)
            await getNewBuildForm()
        }
    }
    
    func getNewBuildForm() async {
        do {
            try await NetworkFederalService.shared.getNewBuildForm()
            await getNewPage()
        } catch {
            print("getNewBuildForm", error)
        }
    }
    
    @ViewBuilder
    var searchParametersView: some View {
        @Bindable var appSettings = dataStore.appSettings
        Section {
            DatePicker("Début", selection: $appSettings.startDate, displayedComponents: .date)
            DatePicker("Fin", selection: $appSettings.endDate, displayedComponents: .date)
            Picker(selection: $appSettings.dayDuration) {
                Text("Aucune").tag(nil as Int?)
                Text(1.formatted()).tag(1 as Int?)
                Text(2.formatted()).tag(2 as Int?)
                Text(3.formatted()).tag(3 as Int?)
            } label: {
                Text("Durée souhaitée (en jours)")
            }
            
            Picker(selection: $appSettings.dayPeriod) {
                ForEach(DayPeriod.allCases) {
                    Text($0.localizedDayPeriodLabel().capitalized).tag($0)
                }
            } label: {
                Text("En semaine ou week-end")
            }

            HStack {
                TextField("Ville", text: $appSettings.city)
                    .onSubmit(of: .text) {
                        locationManager.city = nil
                        locationManager.location = nil
                    }
                    .focused($isFocused)
                    .onChange(of: isFocused) {
                        if isFocused {
                            appSettings.city = ""
                        }
                    }

//                if let city = locationManager.city {
//                    Divider()
//                    Text(city).italic()
//                }
                if locationManager.requestStarted {
                    ProgressView()
                } else if locationManager.manager.authorizationStatus != .restricted {
                    LocationButton {
                        if locationManager.manager.authorizationStatus == .notDetermined {
                            locationRequested = true
                            locationManager.manager.requestWhenInUseAuthorization()
                        } else if locationManager.manager.authorizationStatus == .denied {
                            showingSettingsAlert = true
                        } else {
                            locationRequested = true
                            locationManager.requestLocation()
                        }
                    }
                    .symbolVariant(.fill)
                    .foregroundColor (Color.white)
                    .cornerRadius (20)
                    .font(.system(size: 12))
                }
            }
            
            Picker(selection: $appSettings.distance) {
                Text(distanceLimit(distance:30).formatted()).tag(30.0)
                Text(distanceLimit(distance:50).formatted()).tag(50.0)
                Text(distanceLimit(distance:60).formatted()).tag(60.0)
                Text(distanceLimit(distance:90).formatted()).tag(90.0)
                Text(distanceLimit(distance:150).formatted()).tag(150.0)
                Text(distanceLimit(distance:200).formatted()).tag(200.0)
                Text(distanceLimit(distance:400).formatted()).tag(400.0)
                Text("Aucune").tag(3000.0)
            } label: {
                Text("Distance max")
            }
            
            Picker(selection: $appSettings.sortingOption) {
                Text("Distance").tag("_DIST_")
                Text("Date de début").tag("dateDebut+asc")
                Text("Date de fin").tag("dateFin+asc")
            } label: {
                Text("Trier par")
            }
            
            NavigationLink {
                List([TournamentCategory.men, TournamentCategory.women, TournamentCategory.mix], selection: $appSettings.tournamentCategories) { type in
                    Text(type.localizedLabel())
                }
                .navigationTitle("Catégories")
                .environment(\.editMode, Binding.constant(EditMode.active))
            } label: {
                HStack {
                    Text("Catégorie")
                    Spacer()
                    categoriesLabel
                        .foregroundStyle(.secondary)
                }
            }
            
            NavigationLink {
                List([TournamentLevel.p25, TournamentLevel.p100, TournamentLevel.p250, TournamentLevel.p500, TournamentLevel.p1000, TournamentLevel.p1500, TournamentLevel.p2000], selection: $appSettings.tournamentLevels) { type in
                    Text(type.localizedLevelLabel())
                }
                .navigationTitle("Niveaux")
                .environment(\.editMode, Binding.constant(EditMode.active))
            } label: {
                HStack {
                    Text("Niveau")
                    Spacer()
                    levelsLabel
                        .foregroundStyle(.secondary)
                }
            }
            
            NavigationLink {
                List([FederalTournamentAge.senior, FederalTournamentAge.a45, FederalTournamentAge.a55, FederalTournamentAge.a17_18, FederalTournamentAge.a15_16, FederalTournamentAge.a13_14, FederalTournamentAge.a11_12], selection: $appSettings.tournamentAges) { type in
                    Text(type.localizedFederalAgeLabel())
                }
                .navigationTitle("Limites d'âge")
                .environment(\.editMode, Binding.constant(EditMode.active))
            } label: {
                HStack {
                    Text("Limite d'âge")
                    Spacer()
                    if dataStore.appSettings.tournamentAges.isEmpty || dataStore.appSettings.tournamentAges.count == FederalTournamentAge.allCases.count {
                        Text("Tous les âges")
                            .foregroundStyle(.secondary)
                    } else {
                        Text(ages.map({ $0.localizedFederalAgeLabel()}).joined(separator: ", "))
                            .foregroundStyle(.secondary)
                    }
                }
            }
            
            NavigationLink {
                List(FederalTournamentType.allCases, selection: $appSettings.tournamentTypes) { type in
                    Text(type.localizedLabel())
                }
                .navigationTitle("Types de tournoi")
                .environment(\.editMode, Binding.constant(EditMode.active))
            } label: {
                HStack {
                    Text("Type de tournoi")
                    Spacer()
                    if dataStore.appSettings.tournamentTypes.isEmpty || dataStore.appSettings.tournamentTypes.count == FederalTournamentType.allCases.count {
                        Text("Tous les types")
                            .foregroundStyle(.secondary)
                    } else {
                        Text(types.map({ $0.localizedLabel()}).joined(separator: ", "))
                            .foregroundStyle(.secondary)
                    }
                }
            }
            
            Picker(selection: $appSettings.nationalCup) {
                Text("N'importe").tag(false)
                Text("Uniquement").tag(true)
            } label: {
                Text("Circuit National Padel Cup")
            }
        } header: {
            Text("Critères de recherche")
        }
        .headerProminence(.increased)
        .disabled(searching)
    }
    
    var categoriesLabel: some View {
        if dataStore.appSettings.tournamentCategories.isEmpty || dataStore.appSettings.tournamentCategories.count == TournamentCategory.allCases.count {
            Text("Toutes les catégories")
        } else {
            Text(categories.map({ $0.localizedLabel() }).joined(separator: ", "))
        }
    }
    
    var levelsLabel: some View {
        if dataStore.appSettings.tournamentLevels.isEmpty || dataStore.appSettings.tournamentLevels.count == TournamentLevel.allCases.count {
            Text("Tous les niveaux")
        } else {
            Text(levels.map({ $0.localizedLevelLabel() }).joined(separator: ", "))
        }
    }
    
    @ViewBuilder
    var searchParametersSummaryView: some View {
        VStack(alignment: .leading) {
            HStack {
                Text("Lieu")
                Spacer()
                Text(dataStore.appSettings.city)
                if dataStore.appSettings.distance >= 3000 {
                    Text("sans limite de distance")
                } else {
                    Text("à moins de " + distanceLimit.formatted())
                }
            }
            HStack {
                Text("Période")
                Spacer()
                Text("Du")
                Text(dataStore.appSettings.startDate.twoDigitsYearFormatted)
                Text("Au")
                Text(dataStore.appSettings.endDate.twoDigitsYearFormatted)
            }
            HStack {
                Text("Niveau")
                Spacer()
                levelsLabel
            }
            HStack {
                Text("Catégorie")
                Spacer()
                categoriesLabel
            }
            
            HStack {
                Text("Tri")
                Spacer()
                Text(sortingOptionLabel)
            }
        }
    }
    
    var sortingOptionLabel: String {
        switch dataStore.appSettings.sortingOption {
        case "_DIST_": return "Distance"
        case "dateDebut+asc": return "Date de début"
        case "dateFin+asc": return "Date de fin"
        default:
            return "Distance"
        }
    }
    
    private func _openSettings() {
        guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else {
            return
        }
        UIApplication.shared.open(settingsURL)
    }

}
