//
//  PadelClubApp.swift
//  PadelClub
//
//  Created by Laurent Morvillier on 02/02/2024.
//

import SwiftUI
import LeStorage
import TipKit

@main
struct PadelClubApp: App {
    let persistenceController = PersistenceController.shared
    @State private var navigationViewModel = NavigationViewModel()
    @StateObject var networkMonitor: NetworkMonitor = NetworkMonitor()
    @StateObject var dataStore = DataStore.shared
    @State private var registrationError: RegistrationError? = nil
    @State private var importObserverViewModel = ImportObserver()
    @State private var showDisconnectionAlert: Bool = false
    @Environment(\.horizontalSizeClass) var horizontalSizeClass

    @State var requiredVersion: String? = nil
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var presentError: Binding<Bool> {
        Binding {
            registrationError != nil
        } set: { value in
            if value == false {
                registrationError = nil
            }
        }
    }
    
    enum RegistrationError: LocalizedError {
        case badActivationLink
        case activationFailed
        
        var errorDescription: String? {
            switch self {
            case .badActivationLink:
                return "Le lien d'activation n'a pas fonctionné"
            case .activationFailed:
                return "L'activation de votre compte n'a pas fonctionné"
            }
        }
    }
    
    static var appVersion: String {
        let dictionary = Bundle.main.infoDictionary!
        let version = dictionary["CFBundleShortVersionString"] as! String
        let build = dictionary["CFBundleVersion"] as! String
#if DEBUG
        return "\(version) (\(build)) Debug"
#elseif TESTFLIGHT
        return "\(version) (\(build)) TestFlight"
#elseif PRODTEST
        return "\(version) (\(build)) ProdTest"
#else
        return "\(version) (\(build))"
#endif
    }

    var body: some Scene {
        WindowGroup {
            
            if let requiredVersion {
                DownloadNewVersionView(version: requiredVersion)
            } else {
                MainView()
                    .environment(\.horizontalSizeClass, .compact)
                    .alert(isPresented: presentError, error: registrationError) {
                        Button("Contactez-nous") {
                            _openMail()
                        }
                        Button("Annuler", role: .cancel) {
                            registrationError = nil
                        }
                    }
                    .onOpenURL { url in
#if targetEnvironment(simulator)
#else
                        _handleIncomingURL(url)
#endif
                    }
                    .environmentObject(networkMonitor)
                    .environmentObject(dataStore)
                    .environment(importObserverViewModel)
                    .environment(navigationViewModel)
                    .accentColor(.master)
                    .onAppear {
                        self._checkVersion()
                        
                        if ManualPatcher.patchIfPossible(.disconnect) == true {
                            self.showDisconnectionAlert = true
                        }
#if DEBUG
                        print("Running in Debug mode")
#elseif TESTFLIGHT
                        print("Running in TestFlight mode")
#elseif PRODTEST
                        print("Running in ProdTest mode")
#else
                        print("Running in Release mode")
#endif
                        networkMonitor.checkConnection()
                        self._onAppear()
                        print(PersistenceController.getModelVersion())
                    }
                    .alert(isPresented: self.$showDisconnectionAlert, content: {
                        Alert(title: Text("Vous avez été déconnecté. Veuillez vous reconnecter pour récupérer vos données."))
                    })
                    .task {
                        
//                        try? Tips.resetDatastore()
                        
                        try? Tips.configure([
                            .displayFrequency(.immediate),
                            .datastoreLocation(.applicationDefault)
                        ])
                    }
                    .environment(\.managedObjectContext, persistenceController.localContainer.viewContext)
            }
        }
    }
    
    fileprivate func _checkVersion() {
        Task.detached(priority: .high) {
            if let requiredVersion = await self._retrieveRequiredVersion() {
                let cleanedRequired = requiredVersion.replacingOccurrences(of: "\n", with: "")
                Logger.log(">>> REQUIRED VERSION = \(requiredVersion)")
                if let currentVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
                    await MainActor.run {
                        if VersionComparator.compare(cleanedRequired, currentVersion) == 1 {
                            self.requiredVersion = cleanedRequired
                        }
                    }
                }
            }
        }
    }
    
    fileprivate func _retrieveRequiredVersion() async -> String? {
        let requiredVersionURL = URLs.main.extend(path: "static/misc/required-version.txt")
        
        do {
            let (data, _) = try await URLSession.shared.data(from: requiredVersionURL)
            return String(data: data, encoding: .utf8)
        } catch {
            Logger.log("Error fetching required version: \(error)")
            return nil
        }
    }

    private func _handleIncomingURL(_ url: URL) {
        // Parse the URL
        let pathComponents = url.pathComponents
        if url.scheme == "padelclub" && pathComponents.count > 3 && pathComponents[1] == "activate" {
            let uidb64 = pathComponents[2]
            let token = pathComponents[3]
            _activateUser(uidb64: uidb64, token: token)
            print(uidb64, token)
        } else {
            // Handle invalid URL case
            print("Handle invalid URL case")
            registrationError = .badActivationLink
        }
    }
    
    private func _activateUser(uidb64: String, token: String) {
        guard let url = URL(string: "https://\(URLs.activationHost.rawValue)/activate/\(uidb64)/\(token)/") else {
            registrationError = .activationFailed
            return
        }

        URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                print("activation error")
                print(error)
                registrationError = .activationFailed
                return
            }

            DispatchQueue.main.async {
                dataStore.appSettings.didRegisterAccount = true
                dataStore.appSettingsStorage.write()

                if navigationViewModel.selectedTab != .umpire {
                    navigationViewModel.selectedTab = .umpire
                }
                
                if navigationViewModel.umpirePath.isEmpty {
                    navigationViewModel.umpirePath.append(UmpireView.UmpireScreen.login)
                } else if navigationViewModel.umpirePath.last! != .login {
                    navigationViewModel.umpirePath.removeAll()
                    navigationViewModel.umpirePath.append(UmpireView.UmpireScreen.login)
                }
            }
        }.resume()
    }

    fileprivate func _onAppear() {
        let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        Logger.log("doc dir = \(docURL.absoluteString)")
        UserDefaults.standard.set(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable")
        
//        AppDelegate.askPermissions()
        
    }
    
    
    private func _openMail(emailTo: String = "support@padelclub.app", subject: String = "Support Padel Club") {
        if let url = URL(string: "mailto:\(emailTo)?subject=\(subject)"), UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        }
    }
}


struct DownloadNewVersionView: View {
    
    var version: String
    
    var body: some View {
        
        VStack {
//            AngledStripesBackground()
            Spacer()
            VStack(spacing: 20.0) {
                Text("Veuillez télécharger la nouvelle version de Padel Club pour continuer à vous servir de l'app !")
                    .fontWeight(.semibold)
                    .foregroundStyle(.white)
                    .padding()
                    .background(.logoRed)
                    .clipShape(.buttonBorder)
//                    .padding(32.0)

                VStack(alignment: .center, spacing: 0.0
                ) {
                    Text("Version \(self.version)")
                        .fontWeight(.bold)

                    Image(systemName: "square.and.arrow.down").font(.title)
                }.padding().background(.logoYellow)
                    .clipShape(.buttonBorder)

            }.frame(maxWidth: .infinity)
            .foregroundStyle(.logoBackground)
            .fontWeight(.medium)
                .multilineTextAlignment(.center)
                .padding(.horizontal, 36.0)
            Image("logo").padding(.vertical, 50.0)
            Spacer()
        }
        .background(.logoBackground)
            .onTapGesture {
                UIApplication.shared.open(URLs.appStore.url)
            }
        
    }
    
}

struct DisconnectionAlertView: View {
    var body: some View {
        Text("Vous avez été déconnecté. Veuillez vous reconnecter pour récupérer vos données.").multilineTextAlignment(.center).padding()
    }
}

#Preview {
    DownloadNewVersionView(version: "1.2")
}
