//
//  CallView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 16/04/2024.
//

import SwiftUI
import LeStorage

struct CallView: View {
    
    struct CallStatusView: View {
        let count: Int
        let total: Int
        let startDate: Date?

        var body: some View {
            VStack(spacing: 0) {
                HStack {
                    if let startDate {
                        Text(startDate.formattedAsHourMinute())
                    } else {
                        Text("Aucun horaire").font(.body)
                    }
                    Spacer()
                    Text("\(count.formatted())/\(total.formatted())")
                }
                .font(.largeTitle)
                HStack {
                    if let startDate {
                        Text(startDate.formatted(.dateTime.weekday().day(.twoDigits).month().year()))
                    }
                    Spacer()
                    Text("convoquées au bon horaire")
                }
                .font(.caption)
                .foregroundColor(.secondary)
            }
        }
    }
    
    struct TeamView: View {
        let team: TeamRegistration
        
        var body: some View {
            TeamRowView(team: team, displayCallDate: true)
        }
    }
    
    @EnvironmentObject var dataStore: DataStore
    @EnvironmentObject var networkMonitor: NetworkMonitor
    @Environment(Tournament.self) var tournament: Tournament
    
    var teams: [TeamRegistration]
    let callDate: Date
    let matchFormat: MatchFormat
    let roundLabel: String
    
    @State private var contactType: ContactType? = nil
    @State private var sentError: ContactManagerError? = nil

    @State var showSubscriptionView: Bool = false
    @State var showUserCreationView: Bool = false

    @State var summonParamByMessage: Bool = false
    @State var summonParamReSummon: Bool = false
    
    var messageSentFailed: Binding<Bool> {
        Binding {
            sentError != nil
        } set: { newValue in
            if newValue == false {
                sentError = nil
            }
        }
    }
    
    private func _called(_ success: Bool) {
        if success {
            self.teams.forEach { team in
                team.callDate = callDate
            }
            do {
                try dataStore.teamRegistrations.addOrUpdate(contentOfs: teams)
            } catch {
                Logger.error(error)
            }
        }
    }
    
    func finalMessage(reSummon: Bool) -> String {
        ContactType.callingMessage(tournament: tournament, startDate: callDate, roundLabel: roundLabel, matchFormat: matchFormat, reSummon: reSummon)
    }
    
    var reSummon: Bool {
        return self.teams.allSatisfy({ $0.called() })
    }
    
    var body: some View {
        let callWord : String = (reSummon ? "Reconvoquer" : "Convoquer")
        HStack {
            if self.teams.count == 1 {
                if let previousCallDate = teams.first?.callDate, Calendar.current.compare(previousCallDate, to: callDate, toGranularity: .minute) != .orderedSame {
                    Text("Reconvoquer \(self.callDate.localizedDate()) par")
                } else {
                    Text("\(callWord) cette paire par")
                }
            } else {
                Text("\(callWord) ces \(self.teams.count) paires par")
            }
            
            self._summonMenu(byMessage: true)
            Text("ou")
            self._summonMenu(byMessage: false)
        }
        .font(.subheadline)
        .buttonStyle(.borderless)
        .alert("Un problème est survenu", isPresented: messageSentFailed) {
            Button("OK") {
            }
        } message: {
            Text(self._failureMessage())
        }
        .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:
                            if networkMonitor.connected == false {
                                self.sentError = .messageNotSent
                            } else {
                                self._called(true)
                            }
                        @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:
                            if networkMonitor.connected == false {
                                self.contactType = nil
                                self.sentError = .mailNotSent
                            } else {
                                self._called(true)
                            }
                        @unknown default:
                            break
                        }
                    }
                }
            }
            .tint(.master)
        }
        .sheet(isPresented: self.$showSubscriptionView, content: {
            NavigationStack {
                SubscriptionView(isPresented: self.$showSubscriptionView, showLackOfPlanMessage: true)
            }
        })
        .sheet(isPresented: self.$showUserCreationView, content: {
            NavigationStack {
                LoginView { _ in
                    self.showUserCreationView = false
                    self._summon(byMessage: self.summonParamByMessage,
                                 reSummon: self.summonParamByMessage)
                }
            }
        })
    }
    
    fileprivate func _failureMessage() -> String {
        return [networkMonitor.connected == false ? "L'appareil n'est pas connecté à internet." as String? : nil, 
                sentError == .mailNotSent ? "Le mail est dans la boîte d'envoi de l'app Mail. Vérifiez son état dans l'app Mail avant d'essayer de le renvoyer." as String? : nil,
                (sentError == .messageFailed || sentError == .messageNotSent) ? "Le SMS n'a pas été envoyé" as String? : nil,
                sentError == .mailFailed ? "Le mail n'a pas été envoyé" as String? : nil]
            .compacted().joined(separator: "\n")
    }
    
    @ViewBuilder
    private func _summonMenu(byMessage: Bool) -> some View {
        if self.reSummon {
            Menu {
                Button("Convoquer") {
                    self._summon(byMessage: byMessage, reSummon: false)
                }
                
                Button("Re-convoquer") {
                    self._summon(byMessage: byMessage, reSummon: true)
                }

            } label: {
                Text(byMessage ? "sms" : "mail")
                    .underline()
            }
        } else {
            FooterButtonView(byMessage ? "sms" : "mail") {
                self._summon(byMessage: byMessage, reSummon: false)
            }
        }
    }
    
    private func _summon(byMessage: Bool, reSummon: Bool) {
        self.summonParamByMessage = byMessage
        self.summonParamReSummon = reSummon
        self._verifyUser {
            self._payTournamentAndExecute {
                if byMessage {
                    self._contactByMessage(reSummon: reSummon)
                } else {
                    self._contactByMail(reSummon: reSummon)
                }
            }
        }
    }

    fileprivate func _verifyUser(_ handler: () -> ()) {
        if Store.main.userId != nil {
            handler()
        } else {
            self.showUserCreationView = true
        }
    }
    
    fileprivate func _payTournamentAndExecute(_ handler: () -> ()) {
        do {
            try self.tournament.payIfNecessary()
            handler()
        } catch {
            self.showSubscriptionView = true
        }
    }
    
    fileprivate func _contactByMessage(reSummon: Bool) {
        self.contactType = .message(date: callDate, 
                                    recipients: teams.flatMap { $0.getPhoneNumbers() },
                                    body: finalMessage(reSummon: reSummon),
                                    tournamentBuild: nil)
    }
    
    fileprivate func _contactByMail(reSummon: Bool) {
        self.contactType = .mail(date: callDate,
                            recipients: tournament.umpireMail(),
                            bccRecipients: teams.flatMap { $0.getMail() },
                            body: finalMessage(reSummon: reSummon),
                            subject: tournament.tournamentTitle(),
                            tournamentBuild: nil)
    }

}
