//
//  EventListView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 29/02/2024.
//

import SwiftUI
import LeStorage

struct EventListView: View {
    @EnvironmentObject var dataStore: DataStore
    @Environment(NavigationViewModel.self) var navigation: NavigationViewModel
    @Environment(FederalDataViewModel.self) var federalDataViewModel: FederalDataViewModel
    @Environment(\.viewStyle) var viewStyle

    let tournaments: [FederalTournamentHolder]
    let sortAscending: Bool
    
    @State var showUserSearch: Bool = false

    var lastDataSource: Date? {
        guard let _lastDataSource = dataStore.appSettings.lastDataSource else { return nil }
        return URL.importDateFormatter.date(from: _lastDataSource)
    }
            
    var body: some View {
        let groupedTournamentsByDate = Dictionary(grouping: federalDataViewModel.filteredFederalTournaments(from: tournaments)) { $0.startDate.startOfMonth }
        switch viewStyle {
        case .list:
            let nextMonths = groupedTournamentsByDate.keys.sorted(by: sortAscending ? { $0 < $1 } : { $0 > $1 })

            ForEach(nextMonths.indices, id: \.self) { sectionIndex in
                let section = nextMonths[sectionIndex]
                if let _tournaments = groupedTournamentsByDate[section]?.sorted(by: sortAscending ? { $0.startDate < $1.startDate } : { $0.startDate > $1.startDate }
                ) {
                    Section {
                        _listView(_tournaments)
                    } header: {
                        HStack {
                            Text(section.monthYearFormatted)
                            Spacer()
                            let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments)
                            Text("\(count.formatted()) tournoi" + count.pluralSuffix)
                        }
                    } footer: {
                        if _tournaments.isEmpty == false, let pcTournaments = _tournaments as? [Tournament] {
                            _menuOptions(pcTournaments)
                        }
                    }
                    .headerProminence(.increased)
                }
            }
        case .calendar:
            let nextMonths = _nextMonths()
            ForEach(nextMonths.indices, id: \.self) { sectionIndex in
                let section = nextMonths[sectionIndex]
                let _tournaments = groupedTournamentsByDate[section] ?? []
                Section {
                    CalendarView(date: section, tournaments: _tournaments).id(federalDataViewModel.id)
                } header: {
                    HStack {
                        Text(section.monthYearFormatted)
                        Spacer()
                        let count = federalDataViewModel.countForTournamentBuilds(from: _tournaments)
                        Text("\(count.formatted()) tournoi" + count.pluralSuffix)
                    }
                } footer: {
                    if _tournaments.isEmpty == false, let pcTournaments = _tournaments as? [Tournament] {
                        _menuOptions(pcTournaments)
                    }
                }
                .id(sectionIndex)
                .headerProminence(.increased)
                .task {
                    if navigation.agendaDestination == .tenup
                        && dataStore.user.hasTenupClubs() == true
                        && _tournaments.isEmpty {
                        _gatherFederalTournaments(startDate: section)
                    }
                }
            }
        }
    }
    
    private func _gatherFederalTournaments(startDate: Date) {
//        isGatheringFederalTournaments = true
        Task {
            do {
                let clubs : [Club] = dataStore.user.clubsObjects()
                try await federalDataViewModel.gatherTournaments(clubs: clubs.filter { $0.code != nil }, startDate: startDate, endDate: startDate.endOfMonth)
            } catch {
                Logger.error(error)
//                self.error = error
            }
//            isGatheringFederalTournaments = false
        }
    }
    
    private func _menuOptions(_ pcTournaments: [Tournament]) -> some View {
        Menu {
            _options(pcTournaments)
        } label: {
            Text("Options rapides pour ce mois")
                .underline()
        }
    }
    
    @ViewBuilder
    private func _options(_ pcTournaments: [Tournament]) -> some View {
        if let lastDataSource, pcTournaments.anySatisfy({ $0.rankSourceShouldBeRefreshed() != nil && $0.hasEnded() == false }) {
            Menu {
                Button {
                    Task {
                        do {
                            
                            let dataURLs = SourceFileManager.shared.allFiles.filter { $0.dateFromPath == lastDataSource }
                            guard !dataURLs.isEmpty else { return } // Early return if no files found

                            let sources = dataURLs.map { CSVParser(url: $0) }
                            let chunkedParsers = try await chunkAllSources(sources: sources, size: 10000)

                            try await pcTournaments.concurrentForEach { tournament in
                                if let mostRecentDate = tournament.rankSourceShouldBeRefreshed() {
                                    try await tournament.updateRank(to: mostRecentDate, forceRefreshLockWeight: false, providedSources: chunkedParsers)
                                }
                            }
                            
                            try chunkedParsers.forEach { chunk in
                                try FileManager.default.removeItem(at: chunk.url)
                            }
                            
                            try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                        } catch {
                            Logger.error(error)
                        }
                    }
                } label: {
                    Text("M-à-j des classements")
                }
            } label: {
                Text("Classement \(lastDataSource.monthYearFormatted)")
            }
            Divider()
        }
        Menu {
            if pcTournaments.anySatisfy({ $0.isPrivate == true }) {
                Button {
                    pcTournaments.forEach { tournament in
                        tournament.isPrivate = false
                    }
                    do {
                        try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                    } catch {
                        Logger.error(error)
                    }
                } label: {
                    Text("Afficher sur Padel Club")
                }
            }
            
            if pcTournaments.anySatisfy({ $0.isPrivate == false }) {
                Button {
                    pcTournaments.forEach { tournament in
                        tournament.isPrivate = true
                    }
                    do {
                        try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                    } catch {
                        Logger.error(error)
                    }
                } label: {
                    Text("Masquer sur Padel Club")
                }
            }
        } label: {
            Text("Visibilité sur Padel Club")
        }
        Divider()
        if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) || pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true  && $0.hasEnded() == false }) {
            Menu {
                if pcTournaments.anySatisfy({ $0.hasEnded() == false && $0.enableOnlineRegistration == false && $0.onlineRegistrationCanBeEnabled() }) {
                    Button {
                        pcTournaments.forEach { tournament in
                            tournament.enableOnlineRegistration = true
                        }
                        do {
                            try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                        } catch {
                            Logger.error(error)
                        }
                    } label: {
                        Text("Activer")
                    }
                }
                
                if pcTournaments.anySatisfy({ $0.enableOnlineRegistration == true && $0.hasEnded() == false }) {
                    
                    Button {
                        Task {
                            await pcTournaments.concurrentForEach { tournament in
                                await tournament.refreshTeamList(forced: true)
                            }
                        }
                    } label: {
                        Text("M-à-j des inscriptions")
                    }
                    
                    
                    Button {
                        pcTournaments.forEach { tournament in
                            tournament.enableOnlineRegistration = false
                        }
                        do {
                            try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                        } catch {
                            Logger.error(error)
                        }
                    } label: {
                        Text("Désactiver")
                    }
                }
            } label: {
                Text("Inscription en ligne")
            }
        }
        Divider()
        Menu {
            Button {
                pcTournaments.forEach { tournament in
                    tournament.information = nil
                }
                do {
                    try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                } catch {
                    Logger.error(error)
                }
            } label: {
                Text("Effacer les descriptions")
            }
            
            let info = Set(pcTournaments.compactMap { tournament in
                tournament.information?.trimmedMultiline
            }).joined(separator: "\n")
            
            if info.isEmpty == false {
                Button {
                    pcTournaments.forEach { tournament in
                        tournament.information = info
                    }
                    do {
                        try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                    } catch {
                        Logger.error(error)
                    }
                    
                } label: {
                    Text("Mettre '\(info.trunc(length: 12))'")
                }
            }
            
            PasteButton(payloadType: String.self) { strings in
                if let pasteboard = strings.first {
                    pcTournaments.forEach { tournament in
                        tournament.information = pasteboard
                    }
                    do {
                        try dataStore.tournaments.addOrUpdate(contentOfs: pcTournaments)
                    } catch {
                        Logger.error(error)
                    }
                }
            }
        } label: {
            Text("Description des tournois")
        }

    }
    
    private func _nextMonths() -> [Date] {
        let currentDate = Date().startOfMonth
        let uniqueDates = tournaments.map { $0.startDate.startOfMonth }.uniqued().sorted()
        let firstMonthOfDate = uniqueDates.first
        let lastMonthOfDate = uniqueDates.last
        let calendar = Calendar.current

        if let firstMonthOfDate, let lastMonthOfDate {
            if navigation.agendaDestination == .history {
                return calendar.generateMonthRange(startDate: firstMonthOfDate, endDate: lastMonthOfDate).reversed()
            } else if navigation.agendaDestination == .around || navigation.agendaDestination == .tenup  {
                return calendar.generateMonthRange(startDate: firstMonthOfDate, endDate: lastMonthOfDate)
            } else {
                let min = min(currentDate, firstMonthOfDate)
                let max = max(currentDate, lastMonthOfDate)
                return calendar.generateMonthRange(startDate: min, endDate: calendar.addMonths(3, to: max))
            }
        } else {
            return calendar.generateMonthRange(startDate: currentDate, endDate: calendar.addMonths(3, to: currentDate))
        }
    }
    
    private func _listView(_ tournaments: [FederalTournamentHolder]) -> some View {
        ForEach(tournaments, id: \.holderId) { tournamentHolder in
            if let tournament = tournamentHolder as? Tournament {
                _tournamentView(tournament)
            } else if let federalTournament = tournamentHolder as? FederalTournament {
                _federalTournamentView(federalTournament)
            }
        }
    }
    
    private func _tournamentView(_ tournament: Tournament) -> some View {
        NavigationLink(value: tournament) {
            TournamentCellView(tournament: tournament)
                .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name.CollectionDidLoad), perform: { notification in

                    if let store = notification.object as? SyncedCollection<TeamRegistration> {
                        if store.storeId == tournament.id {
                            tournament.lastTeamRefresh = Date()
                        }
                    }
                    
                })
                .id(tournament.lastTeamRefresh)
                .task(priority: .background) {
                    await tournament.refreshTeamList(forced: false)
                }
        }
        .listRowView(isActive: tournament.enableOnlineRegistration, color: .green, hideColorVariation: true)
        .contextMenu {
            if tournament.hasEnded() == false {
                Button {
                    navigation.openTournamentInOrganizer(tournament)
                } label: {
                    Label("Afficher dans le gestionnaire", systemImage: "line.diagonal.arrow")
                }
                
                Divider()

                _options([tournament])

                
            }
        }
        #if DEBUG
        .swipeActions(edge: .trailing, allowsFullSwipe: true) {
            Button(role: .destructive) {
                dataStore.deleteTournament(tournament)
            } label: {
                LabelDelete()
            }
//            Button() {
//                self.showUserSearch = true
//            } label: {
//                ShareLabel().tint(.orange)
//            }

        }
        #endif
    }
    
    private func _federalTournamentView(_ federalTournament: FederalTournament) -> some View {
        TournamentCellView(tournament: federalTournament)
    }

}

//#Preview {
//    EventListView(tournaments: [], viewStyle: .calendar, sortAscending: true)
//}
