//
//  MatchDetailView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 23/03/2024.
//

import SwiftUI
import LeStorage

struct MatchDetailView: View {

    @EnvironmentObject var dataStore: DataStore

    @EnvironmentObject var networkMonitor: NetworkMonitor
    @Environment(\.dismiss) var dismiss
    @Environment(\.matchViewStyle) private var matchViewStyle

    @State private var showLiveScore: Bool = false
    @State private var editScore: Bool = false
    @State private var scoreType: ScoreType?
    @State private var shareStat: Bool = false
    @State private var startDateSetup: MatchDateSetup = .now
    @State private var fieldSetup: MatchFieldSetup = .random
    @State private var broadcasted: Bool = false
    @State private var startDate: Date = Date()
    @State private var endDate: Date = Date()
    @State private var isEditing: Bool = false
    @State private var showDetails: Bool = false
    @State private var contactType: ContactType? = nil
    @State private var sentError: ContactManagerError? = nil
//    @State private var showSubscriptionView: Bool = false
    
    @State var showSubscriptionView: Bool = false
    @State var showUserCreationView: Bool = false
    @State private var presentFollowUpMatch: Bool = false
    @State private var dismissWhenPresentFollowUpMatchIsDismissed: Bool = false
    @State private var presentRanking: Bool = false
    @State private var confirmScoreEdition: Bool = false
    
    var tournamentStore: TournamentStore? {
        return match.tournamentStore
    }
    
    var messageSentFailed: Binding<Bool> {
        Binding {
            sentError != nil
        } set: { newValue in
            if newValue == false {
                sentError = nil
            }
        }
    }

    var match: Match
    
    init(match: Match, updatedField: Int? = nil) {
        self.match = match
        
        if match.hasStarted() == false && (match.startDate == nil || match.courtIndex == nil) {
            _isEditing = State(wrappedValue: true)
        }
        
        if let startDate = match.startDate {
            _startDateSetup = State(wrappedValue: .customDate)
            _startDate = State(wrappedValue: startDate)
        } else if match.isReady() == false {
            _startDateSetup = State(wrappedValue: .customDate)
        }
        
        if let endDate = match.endDate {
            _endDate = State(wrappedValue: endDate)
        }
        
        if let courtIndex = updatedField ?? match.courtIndex {
            _fieldSetup = State(wrappedValue: .field(courtIndex))
        }
    }

    var body: some View {
        List {
            if match.hasWalkoutTeam() == false {
                if match.hasStarted() {
                    quickLookHeader
                } else {
                    startingOptionView
                }
            }
            
            Section {
                MatchSummaryView(match: match)
                    .matchViewStyle(.plainStyle)
            } footer: {
                if match.isEmpty() == false {
                    HStack {
                        FooterButtonView("Détails des joueurs") {
                            showDetails = true
                        }
                        Spacer()
                        if let tournament = match.currentTournament() {
                            MenuWarningView(tournament: tournament, teams: match.teams(), message: match.matchWarningMessage(), subject: match.matchWarningSubject(), contactType: $contactType)
                                .buttonStyle(.borderless)
                        }
                    }
                }
            }
            
            Section {
                RowButtonView("Saisir les résultats", systemImage: "list.clipboard") {
                    self._editScores()
                }
                .disabled(match.teams().count < 2)
            }
            
            if self.match.currentTournament()?.isFree() == false {
                let players = self.match.teams().flatMap { $0.players() }
                let unpaid = players.filter({ $0.hasPaid() == false })
                
                if unpaid.isEmpty == false {
                    Section {
                        DisclosureGroup {
                            ForEach(unpaid) { player in
                                LabeledContent {
                                    if let store = self.tournamentStore {
                                        PlayerPayView(player: player)
                                            .environmentObject(store)
                                    }
                                } label: {
                                    Text(player.playerLabel())
                                }
                            }
                        } label: {
                            LabeledContent {
                                Text(unpaid.count.formatted() + " / " + players.count.formatted())
                            } label: {
                                Text("Encaissement manquant")
                            }
                        }
                    }
                }
            }
            menuView
        }
        .sheet(isPresented: $showDetails) {
            if let store = self.tournamentStore {
                MatchTeamDetailView(match: match).tint(.master)
                    .environmentObject(store)
            } else {
                Text("no store")
            }
        }
        .sheet(isPresented: self.$showSubscriptionView, content: {
            NavigationStack {
                SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
                    .environment(\.colorScheme, .light)
            }
        })
        .sheet(isPresented: self.$showUserCreationView, content: {
            NavigationStack {
                LoginView(reason: LoginReason.loginRequiredForFeature) { _ in
                    self.showUserCreationView = false
                    self._editScores()
                }
            }
        })
        .sheet(isPresented: $presentFollowUpMatch, onDismiss: {
            if dismissWhenPresentFollowUpMatchIsDismissed {
                dismiss()
            }
        }) {
            NavigationStack {
                
                FollowUpMatchView(match: match, dismissWhenPresentFollowUpMatchIsDismissed: $dismissWhenPresentFollowUpMatchIsDismissed)
            }
            .tint(.master)
        }
        .sheet(isPresented: $presentRanking, content: {
            if let currentTournament = match.currentTournament() {
                NavigationStack {
                    TournamentRankView()
                        .environment(currentTournament)
                        .toolbar {
                            ToolbarItem(placement: .topBarLeading) {
                                Button("Retour", role: .cancel) {
                                    presentRanking = false
                                    dismiss()
                                }
                            }
                        }
                }
                .tint(.master)
            }
        })
        .sheet(item: $scoreType, onDismiss: {
            if match.hasEnded(), confirmScoreEdition {
                confirmScoreEdition = false
                if match.index == 0, match.isGroupStage() == false, match.roundObject?.parent == nil {
                    presentRanking = true
                } else if match.isGroupStage(), match.currentTournament()?.hasEnded() == true {
                    presentRanking = true
                } else {
                    presentFollowUpMatch = true
                }
            }
        }) { scoreType in
            EditScoreView(match: match, confirmScoreEdition: $confirmScoreEdition)
                .tint(.master)
            
            //            switch scoreType {
            //            case .edition:
            //                let matchDescriptor = MatchDescriptor(match: match)
            //                EditScoreView(matchDescriptor: matchDescriptor)
            //            case .live:
            //                if let score = match.score {
            //                    if score.sets.isEmpty {
            //                        SplashView(score: score)
            //                    } else {
            //                        NewLiveScoringView(score: score)
            //                    }
            //                }
            //            case .prepare:
            //                if match.freeMatchTeams.isEmpty == false {
            //                    EditFreeMatchView(match: match)
            //                } else {
            //                    PrepareMatchView(match: match)
            //                }
            //            case .stat:
            //                if let score = match.score {
            //                    MatchStatView()
            //                        .environmentObject(score)
            //                }
            //            case .health:
            //                HealthKitView(match: match)
            //                    .presentationDetents([.medium])
            //            case .feeling:
            //                if let feedbackData = match.feedbackData {
            //                    FeedbackView(feedbackData: feedbackData)
            //                }
            //            }
            
        }
        .alert("Un problème est survenu", isPresented: messageSentFailed) {
            Button("OK") {
            }
        } message: {
            Text(_networkErrorMessage)
        }
        .sheet(item: $contactType) { contactType in
            Group {
                switch contactType {
                case .message(_, let recipients, let body, _):
                    MessageComposeView(recipients: recipients, body: body) { result in
                        switch result {
                        case .cancelled:
                            break
                        case .failed:
                            self.sentError = .messageFailed
                        case .sent:
                            let uncalledTeams = match.teams().filter { $0.getPhoneNumbers().isEmpty }

                            if networkMonitor.connected == false {
                                self.contactType = nil
                                if uncalledTeams.isEmpty == false {
                                    self.sentError = .uncalledTeams(uncalledTeams)
                                } else {
                                    self.sentError = .messageNotSent
                                }
                            } else {
                                if uncalledTeams.isEmpty == false {
                                    self.sentError = .uncalledTeams(uncalledTeams)
                                }
                            }
                        @unknown default:
                            break
                        }
                    }
                case .mail(_, let recipients, let bccRecipients, let body, let subject, _):
                    MailComposeView(recipients: recipients, bccRecipients: bccRecipients, body: body, subject: subject) { result in
                        switch result {
                        case .cancelled, .saved:
                            self.contactType = nil
                        case .failed:
                            self.contactType = nil
                            self.sentError = .mailFailed
                        case .sent:
                            let uncalledTeams = match.teams().filter { $0.getMail().isEmpty }

                            if networkMonitor.connected == false {
                                self.contactType = nil
                                if uncalledTeams.isEmpty == false {
                                    self.sentError = .uncalledTeams(uncalledTeams)
                                } else {
                                    self.sentError = .mailNotSent
                                }
                            } else {
                                if uncalledTeams.isEmpty == false {
                                    self.sentError = .uncalledTeams(uncalledTeams)
                                }
                            }
                        @unknown default:
                            break
                        }
                    }
                }
            }
            .tint(.master)
        }
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Menu {
//                    Button("Créer les scores") {
//                        let teamsScores = match.getOrCreateTeamScores()
//                        do {
//                            try dataStore.teamScores.addOrUpdate(contentOfs: teamsScores)
//                        } catch {
//                            Logger.error(error)
//                        }
//                    }
                    
                    Toggle(isOn: .init(get: {
                        return match.confirmed
                    }, set: { value in
                        match.confirmed = value
                        save()
                    })) {
                        Text(match.confirmed ? "Confirmé" : "Non confirmé")
                    }

                    Divider()

                    if match.courtIndex != nil {
                        Button(role: .destructive) {
                            match.removeCourt()
                            save()
                        } label: {
                            Text("Supprimer le terrain")
                        }
                    }
                    Button(role: .destructive) {
                        match.startDate = nil
                        match.endDate = nil
                        match.confirmed = false
                        save()
                    } label: {
                        Text("Supprimer l'horaire")
                    }
                    
                    Button(role: .destructive) {
                        match.resetScores()
                        match.resetMatch()
                        match.confirmed = false
                        match.updateFollowingMatchTeamScore()
                        save()
                    } label: {
                        Text("Supprimer les scores")
                    }
                    Divider()
                    Button(role: .destructive) {
                        match.resetTeamScores(outsideOf: [])
                        match.resetMatch()
                        match.confirmed = false
                        save()
                    } label: {
                        Text("Remise-à-zéro")
                    }

                    if match.teamScores.isEmpty == false {
                        Divider()
                        Menu {
                            ForEach(match.teamScores) { teamScore in
                                Button(role: .destructive) {
                                    do {
                                        try tournamentStore?.teamScores.delete(instance: teamScore)
                                    } catch {
                                        Logger.error(error)
                                    }
                                    match.confirmed = false
                                    _saveMatch()
                                } label: {
                                    Text(teamScore.team?.teamLabel() ?? "Aucun nom")
                                }
                            }
                        } label: {
                            Text("Supprimer une équipe")
                        }
                    }
                } label: {
                    LabelOptions()
                }
            }
        }
        .navigationTitle(match.matchTitle())
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
        
    }

    var quickLookHeader: some View {
        Section {
            HStack {
                Menu {
                    Button("Non défini") {
                        match.removeCourt()
                        save()
                    }
                    if let tournament = match.currentTournament() {
                        ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in
                            Button(tournament.courtName(atIndex: courtIndex)) {
                                match.setCourt(courtIndex)
                                save()
                            }
                        }
                    }
                } label: {
                    VStack(alignment: .leading) {
                        Text("terrain").font(.footnote).foregroundStyle(.secondary)
                        if let courtName = match.courtName() {
                            Text(courtName)
                                .foregroundStyle(Color.master)
                                .underline()
                        } else {
                            Text("Choisir")
                                .foregroundStyle(Color.master)
                                .underline()
                        }
                    }
                }
                Spacer()
                MatchDateView(match: match, showPrefix: true)
            }
            .font(.title)
            .buttonStyle(.plain)
        } footer: {
//            if match.hasWalkoutTeam() == false {
//                if let weatherData = match.weatherData {
//                    HStack {
//                        WeatherView(weatherData: weatherData)
//                    }
//                }
//            }
        }
    }
    
    enum ScoreType: Int, Identifiable, Hashable {
        var id: Int {
            self.rawValue
        }
        case edition = 0
        case live = 1
        case prepare = 2
        case stat = 3
        case feeling = 4
        case health = 5
    }
    
    @ViewBuilder
    var menuView: some View {
        if match.hasStarted() {
            Section {
                editionView
            }
        }
        
        NavigationLink {
            EditSharingView(match: match)
        } label: {
            Text("Partage sur les réseaux sociaux")
        }

        if match.currentTournament()?.hasEnded() == false {
            Section {
                RowButtonView("Match à suivre") {
                    presentFollowUpMatch = true
                }
            }
        }
    }
    
    var editionView: some View {
        DisclosureGroup(isExpanded: $isEditing) {
            startingOptionView
        } label: {
            Text("Modifier l'horaire et le terrain")
        }
    }
    
    @ViewBuilder
    var startingOptionView: some View {
        if match.hasEnded() == false {
            let rotationDuration = match.getDuration()
            Picker(selection: $startDateSetup) {
                if match.isReady() {
                    Text("Tout de suite").tag(MatchDateSetup.now)
                    Text("Dans 5 minutes").tag(MatchDateSetup.inMinutes(5))
                    Text("Dans 15 minutes").tag(MatchDateSetup.inMinutes(15))
                }
                Text("Précédente rotation").tag(MatchDateSetup.previousRotation)
                Text("Prochaine rotation").tag(MatchDateSetup.nextRotation)
                Text("À").tag(MatchDateSetup.customDate)
            } label: {
                Text("Horaire")
            }
            .onChange(of: startDateSetup) {
                let date = Date()
                switch startDateSetup {
                case .customDate:
                    break
                case .now:
                    startDate = date
                case .nextRotation:
                    let baseDate = match.startDate ?? date
                    startDate = baseDate.addingTimeInterval(Double(rotationDuration) * 60)
                case .previousRotation:
                    let baseDate = match.startDate ?? date
                    startDate = baseDate.addingTimeInterval(Double(-rotationDuration) * 60)
                case .inMinutes(let minutes):
                    startDate = date.addingTimeInterval(Double(minutes) * 60)
                }
            }
        }
        
        if match.startDate != nil || startDateSetup == .customDate {
            DatePicker("Début", selection: $startDate)
                .datePickerStyle(.compact)
        }
        
        if match.endDate != nil {
            DatePicker("Fin", selection: $endDate)
                .datePickerStyle(.compact)
        }


        Picker(selection: $fieldSetup) {
            Text("Au hasard parmi les libres").tag(MatchFieldSetup.random)
            Text("Au hasard").tag(MatchFieldSetup.fullRandom)
            //Text("Premier disponible").tag(MatchFieldSetup.firstAvailable)
            if let tournament = match.currentTournament() {
                ForEach(0..<tournament.courtCount, id: \.self) { courtIndex in
                    Text(tournament.courtName(atIndex: courtIndex))                            .tag(MatchFieldSetup.field(courtIndex))
                }
            } else {
                ForEach(0..<20, id: \.self) { courtIndex in
                    Text(Court.courtIndexedTitle(atIndex: courtIndex))                            .tag(MatchFieldSetup.field(courtIndex))
                }
            }
        } label: {
            Text("Terrain")
        }
        .onChange(of: fieldSetup) {
            if let courtIndex = fieldSetup.courtIndex {
                match.setCourt(courtIndex)
            } else {
                match.removeCourt()
            }
            _saveMatch()
        }
        
        RowButtonView("Valider") {
            match.validateMatch(fromStartDate: startDateSetup == .now ? Date().withoutSeconds() : startDate, toEndDate: endDate, fieldSetup: fieldSetup)

            save()
            
            isEditing.toggle()
            
            if match.hasStarted() == false {
                dismiss()
            }
        }
    }
    
    fileprivate func _editScores() {
        if match.isReady() == false && match.teams().count == 2 {
            let teamsScores = match.getOrCreateTeamScores()
            do {
                try tournamentStore?.teamScores.addOrUpdate(contentOfs: teamsScores)
            } catch {
                Logger.error(error)
            }
        }

        self._verifyUser {
            self._payTournamentAndExecute {
                self.scoreType = .edition
            }
        }
    }
    
    fileprivate func _verifyUser(_ handler: () -> ()) {
        if StoreCenter.main.userId != nil {
            handler()
        } else {
            self.showUserCreationView = true
        }
    }
    
    fileprivate func _payTournamentAndExecute(_ handler: () -> ()) {
        guard let tournament = match.currentTournament() else { fatalError("missing tournament") }

        do {
            try tournament.payIfNecessary()
            handler()
        } catch {
            self.showSubscriptionView = true
        }
    }
    
    private func save() {
        if let startDate = match.startDate, let tournament = match.currentTournament() {
            if startDate < tournament.startDate {
                tournament.startDate = startDate
            }
            do {
                try dataStore.tournaments.addOrUpdate(instance: tournament)
            } catch {
                Logger.error(error)
            }
        }
        
        _saveMatch()
    }
    
    private func _saveMatch() {
        do {
            try tournamentStore?.matches.addOrUpdate(instance: match)
        } catch {
            Logger.error(error)
        }
    }
    
    private var _networkErrorMessage: String {
        ContactManagerError.getNetworkErrorMessage(sentError: sentError, networkMonitorConnected: networkMonitor.connected)
    }
}

//#Preview {
//    MatchDetailView(match: Match.mock(), matchViewStyle: .standardStyle)
//}
