//
//  AppDelegate.swift
//  NearbyStores
//
//  Created by Amine on 5/19/18.
//  Copyright © 2018 Amine. All rights reserved.
//

import UIKit
import Firebase
import FirebaseMessaging
import UserNotifications
import SwiftEventBus
import GoogleMaps
import RealmSwift
import GooglePlaces
import AssistantKit


import Firebase
import GoogleSignIn
import FirebaseAuth
import FBSDKLoginKit


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?
    let gcmMessageIDKey = "gcm.message_id"
    
    
    
    func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
              // Perform any operations when the user disconnects from app here.
              // ...
          }
       
       
       func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
             let handled: Bool = ApplicationDelegate.shared.application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
             //IQKeyboardManager.shared().isEnabled = true
             // Add any custom logic here.
             return handled
        }


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)
        
        GMSPlacesClient.provideAPIKey(AppConfig.GOOGLE_PLACES_KEY)
        GMSServices.provideAPIKey(AppConfig.GOOGLE_PLACES_KEY)
              

         Utils.printDebug("Fonts=====================")
        for family in UIFont.familyNames.sorted(){
            let names = UIFont.fontNames(forFamilyName: family)
            Utils.printDebug("Fonts \(family) => \(names)")
        }
        
        
        //setup default unit
        let unit = LocalData.getValue(key: Settings.Keys.DISTANCE_UNIT, defaultValue: AppConfig.distanceUnit)
        AppConfig.distanceUnit = unit
        
        
        //init app settings
        let first_time = LocalData.getValue(key: "first_time", defaultValue: 1)
        if first_time == 0{
            LocalData.setValue(key: Settings.Keys.RECEIVE_NOTIFICATION, value: true)
            LocalData.setValue(key: Settings.Keys.RECEIVE_NOTIFICATION, value: true)
            LocalData.setValue(key: Settings.Keys.RECEIVE_NOTIFICATION, value: true)
            LocalData.setValue(key: Settings.Keys.RECEIVE_NOTIFICATION, value: true)
            LocalData.setValue(key: Settings.Keys.RECEIVE_NOTIFICATION, value: true)
            LocalData.setValue(key: "first_time", value: 1)
        }
        
       
        //UIApplication.shared.statusBarStyle = .lightContent
        
        GMSServices.provideAPIKey(AppConfig.GOOGLE_MAPS_KEY)
        
        FirebaseApp.configure()
        
        
        GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
            if error != nil || user == nil {
              // Show the app's signed-out state.
            } else {
              // Show the app's signed-in state.
            }
          }
        
        Messaging.messaging().delegate = self
    
        // [START register_for_notifications]
        if #available(iOS 10.0, *) {
            
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })

        } else {

            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)

        }
        
       application.registerForRemoteNotifications()
        
        self.setup(application: application)

        let config = Realm.Configuration(
            // Set the new schema version. This must be greater than the previously used
            // version (if you've never set a schema version before, the version is 0).
            schemaVersion: 80,
            
            // Set the block which will be called automatically when opening a Realm with
            // a schema version lower than the one set above
            migrationBlock: { migration, oldSchemaVersion in
                // We haven’t migrated anything yet, so oldSchemaVersion == 0
                if (oldSchemaVersion < 1) {
                    // Nothing to do!
                    // Realm will automatically detect new properties and removed properties
                    // And will update the schema on disk automatically
                }
        })
        
        // Tell Realm to use this new configuration object for the default Realm
        Realm.Configuration.defaultConfiguration = config

        
        return true
    }
    
    //deep linking
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        
        
        //setup for firebase auth
        GIDSignIn.sharedInstance.handle(url)
        ApplicationDelegate.shared.application(
                   app,
                   open: url,
                   sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
                   annotation: options[UIApplication.OpenURLOptionsKey.annotation]
        )
        
        
        
        Utils.printDebug("Deep Linking \(url.absoluteURL)")
        Utils.printDebug("Deep Linking \(url.path)")
        
        if let hurl = url.host{
            if hurl == AppConfig.DeepLinking.host{
                //check paths
                    //check dtore
                if let id = Utils.getIdFromPath(path: url.path, prefix: "store"){
                    //open store activity
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()) {
                        SwiftEventBus.post("open_view_store", sender:["oid":id] )
                    }
                    
                }else if let id = Utils.getIdFromPath(path: url.path, prefix: "product"){
                    //open product activity
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()) {
                        SwiftEventBus.post("open_view_product", sender:["oid":id] )
                    }
                    
                }else if let id = Utils.getIdFromPath(path: url.path, prefix: "offer"){
                    //open product activity
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()) {
                        SwiftEventBus.post("open_view_offer", sender:["oid":id] )
                    }
                    
                }else if let id = Utils.getIdFromPath(path: url.path, prefix: "event"){
                    //open event activity
                    
                    DispatchQueue.main.asyncAfter(deadline: .now()) {
                        SwiftEventBus.post("open_view_event", sender:["oid":id] )
                    }
                    
                }
                
                
                
            }
        }
        
        return true
    }
    
   
    

    // [END receive_message]
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }
    
    // This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
    // If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
    // the FCM registration token.
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("APNs token retrieved: \(deviceToken)")
        
        // Pass device token to auth
        if AppConfig.DEBUG{
            Auth.auth().setAPNSToken(deviceToken, type: .sandbox)
        }else{
            Auth.auth().setAPNSToken(deviceToken, type: .prod)
        }
        
        
        // With swizzling disabled you must set the APNs token here.
         Messaging.messaging().apnsToken = deviceToken
    }
    
    
    
    func setup(application: UIApplication)  {
        
       
      
        let statusBarBackgroundView = UIView()
       
    
        if(AppStyle.Config.uiColor == AppStyle.uiColor.light){
            if #available(iOS 13.0, *) {
                UIApplication.shared.statusBarStyle = .darkContent
            } else {
                // Fallback on earlier versions
            }
            UINavigationBar.appearance().barTintColor = Colors.white
            statusBarBackgroundView.backgroundColor = Colors.white
        }else{
            if #available(iOS 13.0, *) {
                UIApplication.shared.statusBarStyle = .lightContent
            } else {
                // Fallback on earlier versions
            }
             
            statusBarBackgroundView.backgroundColor = Colors.darkColor
            UINavigationBar.appearance().barTintColor = Colors.primaryColor
        }
               
        
        window?.addSubview(statusBarBackgroundView)
        window?.addConstraintsWithFormat(format: "H:|[v0]|", views: statusBarBackgroundView)
        window?.addConstraintsWithFormat(format: "V:|[v0(20)]", views: statusBarBackgroundView)
        
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
    
    
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
    {
        return UIInterfaceOrientationMask.portrait
    }
    
    
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
        
        Utils.printDebug("Firebase registration token: \(fcmToken)")
        
        //save token in the local database
        LocalData.setValue(key: "firebase_fcm", value: fcmToken)
        
        //refresh token in the server
        CampaignApiCall.guest_api_refresh(token: fcmToken)
        
        
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }
    
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        
        guard let token = fcmToken else{
            return
        }
        
        Utils.printDebug("Firebase registration token: \(token)")
        
        //save token in the local database
        LocalData.setValue(key: "firebase_fcm", value: token)
        
        //refresh token in the server
        CampaignApiCall.guest_api_refresh(token: token)
        
    }
    
    
    
    func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
        
        application.registerForRemoteNotifications()
    }
    
    func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
        
    }
    
    
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        
        if let text = userInfo["text"] {
            
            let icdParser = InComingDataParser(content: text as? String)
            icdParser.proccess()
            
        }
        
        // Print full message.
        print(userInfo)
        
    }
    

    /*
    * RECEIVE NOTIFICATION WHEN THE APP RUNNING IN THE BACKGROUND
    */
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        // If you are receiving a notification message while your app is in the background,
        // this callback will not be fired till the user taps on the notification launching the application.
        // TODO: Handle data of notification
        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        
        
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
        
        if let messageID = userInfo[gcmMessageIDKey] {
            Utils.printDebug("Message ID: \(messageID)")
        }
        
        if let text = userInfo["text"] {
            let icdParser = InComingDataParser(content: text as? String)
            icdParser.proccess(pushNotification: true)
            completionHandler(UIBackgroundFetchResult.newData)
            return
           
        }
        
        Utils.printDebug("\(userInfo)")
        
        completionHandler(UIBackgroundFetchResult.newData)
    }
    
   
    /*
     * RECEIVE NOTIFICATION WHEN THE APP RUNNING IN THE FOREGROUND
     */
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
        

        // With swizzling disabled you must let Messaging know about the message, for Analytics

        Messaging.messaging().appDidReceiveMessage(userInfo)
     
        if let text = userInfo["text"] {
            Utils.printDebug("__userNotificationCenter: \(text)")
            let icdParser = InComingDataParser(content: text as? String)
            icdParser.proccess()
            return
        }
        completionHandler([.alert,.sound])
    }
    
    
    /*
     * CLICK EVENT ON NOTIFICATION
     */
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        
        
            
        let userInfo = response.notification.request.content.userInfo
        
        ServerApi.sync(key: "RemoteNotification", message: "userNotificationCenter@2: \(userInfo)<br><br>")
              
        
        
        if let text = userInfo["text"] {
            Utils.printDebug("_RePush DATA: \(text)")
            let icdParser = InComingDataParser(content: text as? String)
            icdParser.proccess(pushNotification: true)
            return
        }
        
        
        let notification_identifier:String = response.notification.request.identifier
        
        let status: UIApplication.State = UIApplication.shared.applicationState // or use  let state =  UIApplication.sharedApplication().applicationState
    
        if notification_identifier == InComingDataParser.tag_new_message {
            
            //update badge
            SwiftEventBus.post("on_badge_refresh", sender: true)
            
            DispatchQueue.main.asyncAfter(deadline: .now()) {
                
                if MainViewController.isAppear {
                    for index in 0...AppConfig.HomeStruct.Pages.count{
                        if AppConfig.HomeStruct.Pages[index] == AppConfig.HomeStruct.Tags.TAG_INBOX{
                            SwiftEventBus.post("on_main_redirect", sender: index)
                            break
                        }
                    }
                }
                
            }
  
            
        }else if notification_identifier ==  CampaignParser.OFFER {
            
           
            
            if let cid = NotificationManager.last_received_cid{
                CampaignApiCall.markView(cid: cid)
            }
            
           
            
            if status == .active{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()) {
                    SwiftEventBus.post("open_view_"+CampaignParser.OFFER, sender:["oid":oid,"cid":cid])
                }

            }else if status == .background{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+1) {
                    SwiftEventBus.post("open_view_"+CampaignParser.OFFER, sender:["oid":oid,"cid":cid])
                }
                
            }else{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+3) {
                    SwiftEventBus.post("open_view_"+CampaignParser.OFFER, sender:["oid":oid,"cid":cid])
                }
                
            }
            
            
        }else if notification_identifier ==  CampaignParser.PRODUCT {
            
            
            if let cid = NotificationManager.last_received_cid{
                CampaignApiCall.markView(cid: cid)
            }
            
            
            if status == .active{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()) {
                    SwiftEventBus.post("open_view_"+CampaignParser.PRODUCT, sender:["oid":oid,"cid":cid])
                }

            }else if status == .background{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+1) {
                    SwiftEventBus.post("open_view_"+CampaignParser.PRODUCT, sender:["oid":oid,"cid":cid])
                }
                
            }else{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+3) {
                    SwiftEventBus.post("open_view_"+CampaignParser.PRODUCT, sender:["oid":oid,"cid":cid])
                }
                
            }
            
            
        }else if notification_identifier == CampaignParser.STORE {
            
            if let cid = NotificationManager.last_received_cid{
                CampaignApiCall.markView(cid: cid)
            }
        
            if status == .active{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()) {
                    SwiftEventBus.post("open_view_"+CampaignParser.STORE, sender:["oid":oid,"cid":cid])
                }
                
            }else{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+1) {
                    SwiftEventBus.post("open_view_"+CampaignParser.STORE, sender:["oid":oid,"cid":cid])
                }
                
            }
            
        }else if notification_identifier ==  CampaignParser.EVENT {
            
             if let cid = NotificationManager.last_received_cid{
                CampaignApiCall.markView(cid: cid)
             }
            
            if status == .active{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()) {
                    SwiftEventBus.post("open_view_"+CampaignParser.EVENT, sender:["oid":oid,"cid":cid])
                }
                
            }else if status == .background{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+1) {
                    SwiftEventBus.post("open_view_"+CampaignParser.EVENT, sender:["oid":oid,"cid":cid])
                }
            }else{
                
                let cid = NotificationManager.last_received_cid
                let oid = NotificationManager.last_received_oid
                
                DispatchQueue.main.asyncAfter(deadline: .now()+3) {
                    SwiftEventBus.post("open_view_"+CampaignParser.EVENT, sender:["oid":oid,"cid":cid])
                }
            }
            
            
            
        }
        
        //update badge if user click on iOS notification
        SwiftEventBus.post("decrease_notifications_badge")
        
        //re-init all vars
        NotificationManager.last_received_cid = nil
        NotificationManager.last_received_oid = nil
        NotificationManager.last_received_type = nil
        
        
        completionHandler()
    }


}


extension UIApplication {
    var statusBarView: UIView? {
        if #available(iOS 13.0, *) {
            let view = UIView(frame: UIApplication.shared.statusBarFrame)
            return view
        }else {
            if responds(to: Selector(("statusBar"))) {
                return value(forKey: "statusBar") as? UIView
            }
            return nil
        }
    }
}



// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToNSAttributedStringKeyDictionary(_ input: [String: Any]) -> [NSAttributedString.Key: Any] {
    return Dictionary(uniqueKeysWithValues: input.map { key, value in (NSAttributedString.Key(rawValue: key), value)})
}
