//
//  FileImportView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 24/03/2024.
//

import SwiftUI
import TipKit
import LeStorage

enum FileImportCustomField: Int, Identifiable, CaseIterable {
    var id: Int { self.rawValue }
    
    case sexType
    case teamName
    case lastName
    case firstName
    case rank
    case licenceId
    case clubName
    
    func columnLabel() -> String {
        let columnIndex: Int = self.rawValue + 1
        return columnIndex.formatted()
    }
    
    func descriptionLabel() -> String? {
        switch self {
        case .sexType:
            return "f ou m"
        default:
            return nil
        }
    }
    
    func localizedLabel() -> String {
        switch self {
        case .sexType:
            return "Sexe"
        case .teamName:
            return "Nom de l'équipe"
        case .lastName:
            return "Nom"
        case .firstName:
            return "Prénom"
        case .rank:
            return "Rang"
        case .licenceId:
            return "Licence"
        case .clubName:
            return "Nom du club"
        }
    }
}

struct FileImportView: View {
    @EnvironmentObject var dataStore: DataStore
    @Environment(Tournament.self) var tournament: Tournament
    @Environment(\.dismiss) private var dismiss

    let notFoundAreWalkOutTip = NotFoundAreWalkOutTip()
    
    @State private var fileContent: String?
    @State private var teams: [FileImportManager.TeamHolder] = []
    @State private var isShowing = false
    @State private var didImport = false
    @State private var convertingFile = false
    @State private var errorMessage: String? = nil
    @State private var forceRankUpdate: Bool = false
    
    @State private var selectedOptions: Set<TeamImportStrategy> = Set()
    
    @State private var fileProvider: FileImportManager.FileProvider = .frenchFederation
    @State private var validationInProgress: Bool = false
    @State private var multiImport: Bool = false
    @State private var presentFormatHelperView: Bool = false
    
    private func filteredTeams(tournament: Tournament) -> [FileImportManager.TeamHolder] {
        return teams.filter { $0.tournamentCategory == tournament.tournamentCategory }.sorted(by: \.weight)
    }
    
    private func _deleteTeams() async {
        await MainActor.run {
            do {
                try dataStore.teamRegistrations.delete(contentOfs: tournament.unsortedTeams())
            } catch {
                Logger.error(error)
            }
        }
    }
    
    var body: some View {
        List {
            if teams.isEmpty {
                Section {
                    RowButtonView("Choisir le fichier", systemImage: "square.and.arrow.down") {
                        convertingFile = false
                        isShowing.toggle()
                    }
                }
                
                if tournament.unsortedTeams().count > 0 {
                    RowButtonView("Effacer les équipes déjà inscrites", role: .destructive) {
                        await _deleteTeams()
                    }
                }
                
                Section {
                    Picker(selection: $fileProvider) {
                        ForEach(FileImportManager.FileProvider.allCases) {
                            Text($0.localizedLabel).tag($0)
                        }
                    } label: {
                        Text("Source du fichier")
                    }
                    
                    RowButtonView("Démarrer l'importation") {
                        if let fileContent {
                            do {
                                try await _startImport(fileContent: fileContent)
                            } catch {
                                errorMessage = error.localizedDescription
                            }
                        }
                    }
                    .disabled(fileContent == nil || convertingFile)
                } footer: {
                    if fileProvider == .frenchFederation {
                        let footerString = "Fichier provenant de [beach-padel.app.fft.fr](\(URLs.beachPadel.rawValue))"
                        Text(.init(footerString))
                    } else if fileProvider == .custom {
                        FooterButtonView("Voir le format du fichier") {
                            presentFormatHelperView = true
                        }
                    }
                }
                
                if let tournaments = tournament.eventObject()?.tournaments, tournaments.count > 1, fileProvider == .frenchFederation {
                    Section {
                        RowButtonView("Importer toutes les épreuves") {
                            multiImport = true
                            if let fileContent {
                                do {
                                    try await _startImport(fileContent: fileContent)
                                } catch {
                                    errorMessage = error.localizedDescription
                                }
                            }
                        }
                    } footer: {
                        Text("Ce tournoi possède plusieurs épreuves. Vous pouvez importer les équipes du fichier pour toutes les épreuves d'un coup.")
                    }
                    .disabled(fileContent == nil || convertingFile)
                }
            }
            
//            if filteredTeams.isEmpty == false && tournament.unsortedTeams().isEmpty == false {
//                Section {
//                    ForEach(TeamImportStrategy.allCases, id: \.self) { strategy in
//                        LabeledContent {
//                            Toggle(isOn: .init(get: {
//                                selectedOptions.contains(strategy)
//                            }, set: { selected in
//                                if selected {
//                                    selectedOptions.insert(strategy)
//                                } else {
//                                    selectedOptions.remove(strategy)
//
//                                }
//                            })) {}
//                        } label: {
//                            Text(strategy.titleLabel())
//                            Text(strategy.descriptionLabel())
//                        }
//
//                    }
//                } header: {
//                    Text("Stratégie d'importation")
//                }
//            }
            
            if convertingFile {
                Section {
                    LabeledContent {
                        ProgressView()
                    } label: {
                        Text("Conversion du fichier en cours")
                    }
                }
            }
                        
            if let errorMessage {
                Section {
                    Text(errorMessage)
                } header: {
                    Text("Erreur")
                }
            }
            
//            if tournament.entriesCount > 0 {
//                Section {
//                    if tournament.inscriptionClosed {
//                        Label("Les inscriptions clôturées", systemImage: "lock")
//                        Text("Si le poids des équipes a changé, aucun déplacement entre les poules et le tableau n'est possible. Par contre, le classement sera mis à jour au sein des poules et du tableau, respectivement, en fonction de leur nouveau poids.")
//                        Toggle(isOn: $forceRankUpdate) {
//                            Text("Ne pas en tenir compte")
//                        }
//                    } else {
//                        Label("Les inscriptions sont ouvertes", systemImage: "lock.open")
//                        Text("Si le poids des équipes a changé, le classement de toutes les équipes sera mis à jour en fonction de leur nouveau poids.")
//                    }
//                }
//            }
            
            let filteredTeams = filteredTeams(tournament: tournament)
            if filteredTeams.isEmpty && teams.isEmpty == false && multiImport == false {
                @Bindable var tournament = tournament
                Section {
                    Text("Aucune équipe \(tournament.tournamentCategory.importingRawValue) détectée mais \(teams.count) équipes sont dans le fichier")
                    Picker(selection: $tournament.tournamentCategory) {
                        ForEach(TournamentCategory.allCases) { category in
                            Text(category.importingRawValue).tag(category)
                        }
                    } label: {
                        Text("Modifier la catégorie du tournoi ?")
                    }
                    .onChange(of: tournament.tournamentCategory) {
                        _save()
                    }
                }
            } else if teams.isEmpty && didImport == true {
                Section {
                    ContentUnavailableView("Aucune équipe détectée", systemImage: "person.2.slash")
                }
            } else if didImport {
                let _filteredTeams = filteredTeams
                let previousTeams = tournament.sortedTeams()

                if previousTeams.isEmpty == false {
                    Section {
                        TipView(notFoundAreWalkOutTip)
                            .tipStyle(tint: nil)
                    }
                }
                
                if multiImport, fileProvider == .frenchFederation, let tournaments = tournament.eventObject()?.tournaments, tournaments.count > 1 {
                    ForEach(tournaments) { tournament in
                        let tournamentFilteredTeams = self.filteredTeams(tournament: tournament)

                        Section {
                            RowButtonView("Valider") {
                                await _validate(tournament: tournament)
                            }
                        } header: {
                            Text("\(tournamentFilteredTeams.count.formatted()) équipe\(tournamentFilteredTeams.count.pluralSuffix)")
                        } footer: {
                            Text(tournament.tournamentTitle())
                        }
                    }
                    .headerProminence(.increased)
                } else {
                    Section {
                        LabeledContent {
                            Text(_filteredTeams.count.formatted())
                        } label: {
                            Text("Équipe\(_filteredTeams.count.pluralSuffix) \(tournament.tournamentCategory.importingRawValue) détectée\(_filteredTeams.count.pluralSuffix)")
                        }
                    } footer: {
                        if previousTeams.isEmpty == false {
                            Text("La liste ci-dessous n'est qu'une indication d'évolution par rapport au seul poids d'équipe. Cela ne tient pas compte des dates d'inscriptions, WCs et autres éléments.").foregroundStyle(.logoRed)
                        }
                    }
                    
                    ForEach(_filteredTeams) { team in
                        _teamView(team: team, inTeams: _filteredTeams, previousTeams: previousTeams)
                    }
                }
            }
        }
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
        .sheet(isPresented: $presentFormatHelperView) {
            NavigationStack {
                List {
                    Section {
                        Text("Créer un fichier xls, xlsx ou csv qui contient les colonnes suivantes.")
                        Text("Chaque ligne correspond à un joueur, et chaque groupe de deux lignes correspond à une équipe.")
                        Text("Aucune valeur n'est obligatoire.")
                    }
                    
                    Section {
                        ForEach(FileImportCustomField.allCases) { fileImportCustomField in
                            LabeledContent {
                                Text(fileImportCustomField.localizedLabel())
                            } label: {
                                Text("Colonne \(fileImportCustomField.columnLabel())")
                                if let descriptionLabel = fileImportCustomField.descriptionLabel() {
                                    Text(descriptionLabel)
                                }
                            }
                        }
                    }
                }
                .navigationTitle("Description du format")
                .navigationBarTitleDisplayMode(.inline)
                .toolbarBackground(.visible, for: .navigationBar)
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Button("Fermer") {
                            presentFormatHelperView = false
                        }
                    }
                }
            }
            .tint(.master)
        }
        .fileImporter(isPresented: $isShowing, allowedContentTypes: [.spreadsheet, .commaSeparatedText, .text], allowsMultipleSelection: false, onCompletion: { results in
            
            switch results {
            case .success(let fileurls):
                if let selectedFile = fileurls.first {
                    if selectedFile.startAccessingSecurityScopedResource() {
                        errorMessage = nil
                        teams.removeAll()
                        Task {
                            do {
                                if selectedFile.lastPathComponent.hasSuffix("xls") || selectedFile.lastPathComponent.hasSuffix("xlsx") {
                                    convertingFile = true
                                    fileContent = try await CloudConvert.manager.uploadFile(selectedFile)
                                    convertingFile = false
                                } else {
                                    fileContent = try String(contentsOf: selectedFile)
                                }
                                selectedFile.stopAccessingSecurityScopedResource()
                            } catch {
                                errorMessage = error.localizedDescription
                            }
                        }
                    } else {
                        // Handle denied access
                    }
                }
            case .failure(let error):
                errorMessage = error.localizedDescription
            }
        })

        .onOpenURL { url in
            do {
                fileContent = try String(contentsOf: url)
            } catch {
                errorMessage = error.localizedDescription
            }
        }
        .navigationTitle("Importation")
        .navigationBarTitleDisplayMode(.large)
        .toolbar {
//            ToolbarItem(placement: .bottomBar) {
//                PasteButton(payloadType: String.self) { strings in
//                    guard let string = strings.first else { return }
//                    fileContent = string
//                    fileProvider = .padelClub
//                }
//            }
            ToolbarItem(placement: .cancellationAction) {
                Button("Annuler", role: .cancel) {
                    dismiss()
                }
            }
            
            ToolbarItem(placement: .topBarTrailing) {
                if validationInProgress {
                    ProgressView()
                } else {
                    ButtonValidateView(title: (multiImport ? "Tout Valider" : "Valider")) {
                        validationInProgress = true
                        Task {
                            if let tournaments = tournament.eventObject()?.tournaments, tournaments.count > 1, multiImport {
                                for tournament in tournaments {
                                    await _validate(tournament: tournament)
                                }
                                
                                dismiss()
                            } else {
                                await _validate(tournament: tournament)
                            }
                        }
                    }
                    .disabled(teams.isEmpty)
                }
            }
        }
        .interactiveDismissDisabled(validationInProgress)
        .disabled(validationInProgress)
    }
    
    private func _validate(tournament: Tournament) async {
        let filteredTeams = filteredTeams(tournament: tournament)
        let previousTeams = filteredTeams.compactMap({ $0.previousTeam })
        
        let unfound = Set(tournament.unsortedTeams()).subtracting(Set(previousTeams))
        unfound.forEach { team in
            team.resetPositions()
            team.wildCardBracket = false
            team.wildCardGroupStage = false
            team.walkOut = true
        }
        
        do {
            try dataStore.teamRegistrations.addOrUpdate(contentOfs: unfound)
        } catch {
            Logger.error(error)
        }
        
        tournament.importTeams(filteredTeams)
        if multiImport == false {
            dismiss()
        }
    }
    
    private func _startImport(fileContent: String) async throws {
        await MainActor.run {
            errorMessage = nil
            teams.removeAll()
        }
        if let rankSourceDate = tournament.rankSourceDate, tournament.unrankValue(for: false) == nil || tournament.unrankValue(for: true) == nil {
            await MonthData.calculateCurrentUnrankedValues(mostRecentDateAvailable: rankSourceDate)
        }

        self.teams = try await FileImportManager.shared.createTeams(from: fileContent, tournament: tournament, fileProvider: fileProvider)
        await MainActor.run {
            didImport = true
        }
    }

    @ViewBuilder
    private func _teamView(team: FileImportManager.TeamHolder, inTeams teams: [FileImportManager.TeamHolder], previousTeams: [TeamRegistration]) -> some View {
        
        let newIndex = team.index(in: teams)
        Section {
            HStack {
                VStack(alignment: .leading) {
                    ForEach(team.players.sorted(by: \.computedRank)) {
                        Text($0.playerLabel())
                    }
                }
                Spacer()
                HStack {
                    if let previousTeam = team.previousTeam {
                        Text(previousTeam.formattedSeed(in: previousTeams))
                        Image(systemName: "arrowshape.forward.fill")
                    }
                    Text(team.formattedSeedIndex(index: newIndex))
                }
            }
            if let callDate = team.previousTeam?.callDate, let newDate = tournament.getStartDate(ofSeedIndex: newIndex), callDate != newDate {
                Text("Attention, cette paire a déjà été convoquée à \(callDate.localizedDate())")
                    .foregroundStyle(.red)
                    .italic()
                    .font(.caption)
            }
        }
    }
    
    private func _save() {
        do {
            try dataStore.tournaments.addOrUpdate(instance: tournament)
        } catch {
            Logger.error(error)
        }
    }
}

//#Preview {
//    FileImportView()
//        .environment(Tournament.mock())
//}

enum TeamImportStrategy: CaseIterable {
    case notFoundAreWalkOut
    case deleteBeforeImport
    
    func titleLabel() -> String {
        switch self {
        case .notFoundAreWalkOut:
            "Mettre les équipes manquantes WO"
        case .deleteBeforeImport:
            "Effacer avant d'importer"
        }
    }
    func descriptionLabel() -> String {
        switch self {
        case .notFoundAreWalkOut:
            "Si une équipe déjà présente n'est pas dans la nouvelle liste, elle sera mise à WO"
        case .deleteBeforeImport:
            "Supprime toutes les équipes avant d'importer"
//        case .lockWeight:
//            "Permets de déplacer les équipes avec leur nouveaux classements sans les déplacer entre les blocs (p500+)"
        }
    }
}
