//
//  AppDelegate.swift
//  SodaLive
//
//  Created by klaus on 2023/08/09.
//

import UIKit
import Combine

import notifly_sdk
import AppsFlyerLib
import FBSDKCoreKit
import FirebaseCore
import FirebaseAnalytics
import FirebaseMessaging

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    private let gcmMessageIDKey = "gcm.message_id"
    private let adTrackingRepository = AdTrackingRepository()
    
    private var subscription = Set<AnyCancellable>()
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        FirebaseApp.configure()
        Notifly.initialize(projectId: NOTIFLY_PROJECT_ID, username: NOTIFLY_USERNAME, password: NOTIFLY_PASSWORD)
        Messaging.messaging().delegate = self
        setupAppsFlyer()
        
        // 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 })
        
        application.registerForRemoteNotifications()
        UIApplication.shared.applicationIconBadgeNumber = 0
        
        ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
        AppEvents.shared.activateApp()
        
        return true
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if let type = userInfo["type"] as? String, type == "POINT_GRANTED" {
                NotificationCenter.default.post(name: .pointGranted, object: userInfo["message"])
        } else {
            Messaging.messaging().appDidReceiveMessage(userInfo)
            // Print message ID.
            if let messageID = userInfo[gcmMessageIDKey] {
                DEBUG_LOG("Message ID: \(messageID)")
            }
            
            // Print full message.
            DEBUG_LOG("userInfo: \(userInfo)")
            
            completionHandler(UIBackgroundFetchResult.newData)
        }
    }
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        UserDefaults.set(deviceToken, forKey: .devicePushToken)
        Messaging.messaging().apnsToken = deviceToken
        Notifly.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        Notifly.application(application, didFailToRegisterForRemoteNotificationsWithError: error)
    }
    
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
        AppsFlyerLib.shared().continue(userActivity, restorationHandler: nil)
        return true
    }
    
    private func setupAppsFlyer() {
        if let infoDic = Bundle.main.infoDictionary, let devKey = infoDic["AppsFlyerDevKey"] as? String, let appId = infoDic["AppsFlyerAppID"] as? String {
            AppsFlyerLib.shared().appsFlyerDevKey = devKey
            AppsFlyerLib.shared().appleAppID = appId
        } else {
            AppsFlyerLib.shared().appsFlyerDevKey = "tWF2wbJ5nSkya5Ru9mGcPU"
            AppsFlyerLib.shared().appleAppID = "6461721697"
        }
        
        AppsFlyerLib.shared().waitForATTUserAuthorization(timeoutInterval: 60)
        
        AppsFlyerLib.shared().delegate = self
        AppsFlyerLib.shared().deepLinkDelegate = self
    }
    
    private func logUtmInFirebase() {
        FirebaseTracking.shared.logUtm()
    }
    
    private func adTrackingAppLaunch(pid: String) {
        adTrackingRepository.adTrackingAppLaunch(pid: pid)
            .sink { result in
                switch result {
                case .finished:
                    DEBUG_LOG("finish")
                case .failure(let error):
                    ERROR_LOG(error.localizedDescription)
                }
            } receiveValue: { _ in
            }
            .store(in: &self.subscription)
        
    }
}

extension AppDelegate: AppsFlyerLibDelegate {
    func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) {
        DEBUG_LOG("AppsFlyer Conversion Data: \(conversionInfo)")
        if let status = conversionInfo["af_status"] as? String, status == "Non-organic" {
            let pid = conversionInfo["deep_link_sub1"] as? String ?? ""
            if !pid.isEmpty {
                UserDefaults.set(pid, forKey: .marketingPid)
                adTrackingAppLaunch(pid: pid)
            }
            
            if let utmSource = conversionInfo["deep_link_sub2"] as? String {
                AppState.shared.marketingUtmSource = utmSource
            }
            
            if let utmMedium = conversionInfo["deep_link_sub3"] as? String {
                AppState.shared.marketingUtmMedium = utmMedium
            }
            
            if let utmCampaign = conversionInfo["deep_link_sub4"] as? String {
                AppState.shared.marketingUtmCampaign = utmCampaign
            }
            
            let deepLinkValue = conversionInfo["deep_link_value"] as? String ?? ""
            let deepLinkValueId = Int(conversionInfo["deep_link_sub5"] as? String ?? "") ?? 0
            
            if deepLinkValueId > 0 {
                if deepLinkValue == "series" {
                    AppState.shared.pushSeriesId = deepLinkValueId
                } else if deepLinkValue == "content" {
                    AppState.shared.pushAudioContentId = deepLinkValueId
                } else if deepLinkValue == "live" {
                    AppState.shared.pushRoomId = deepLinkValueId
                } else if deepLinkValue == "channel" {
                    AppState.shared.pushChannelId = deepLinkValueId
                }
            }
            
            logUtmInFirebase()
        }
    }
    
    func onConversionDataFail(_ error: any Error) {
        DEBUG_LOG("AppsFlyer Conversion Data Failed: \(error.localizedDescription)")
    }
}

extension AppDelegate: DeepLinkDelegate {
    func didResolveDeepLink(_ result: DeepLinkResult) {
        switch result.status {
        case .notFound:
            DEBUG_LOG("[AFSDK] Deep link not found")
            return
        case .failure:
            DEBUG_LOG("Error \(result.error!)")
            return
        case .found:
            DEBUG_LOG("[AFSDK] Deep link found")
        }
        
        guard let deepLinkObj:DeepLink = result.deepLink else {
            DEBUG_LOG("[AFSDK] Could not extract deep link object")
            return
        }
        
        let pid = deepLinkObj.clickEvent["deep_link_sub1"] as? String ?? ""
        if !pid.isEmpty {
            UserDefaults.set(pid, forKey: .marketingPid)
            adTrackingAppLaunch(pid: pid)
        }
        
        if let utmSource = deepLinkObj.clickEvent["deep_link_sub2"] as? String {
            AppState.shared.marketingUtmSource = utmSource
        }
        
        if let utmMedium = deepLinkObj.clickEvent["deep_link_sub3"] as? String {
            AppState.shared.marketingUtmMedium = utmMedium
        }
        
        if let utmCampaign = deepLinkObj.clickEvent["deep_link_sub4"] as? String {
            AppState.shared.marketingUtmCampaign = utmCampaign
        }
        
        let deepLinkValue = deepLinkObj.clickEvent["deep_link_value"] as? String ?? ""
        let deepLinkValueId = Int(deepLinkObj.clickEvent["deep_link_sub5"] as? String ?? "") ?? 0
        
        if deepLinkValueId > 0 {
            if deepLinkValue == "series" {
                AppState.shared.pushSeriesId = deepLinkValueId
            } else if deepLinkValue == "content" {
                AppState.shared.pushAudioContentId = deepLinkValueId
            } else if deepLinkValue == "live" {
                AppState.shared.pushRoomId = deepLinkValueId
            } else if deepLinkValue == "channel" {
                AppState.shared.pushChannelId = deepLinkValueId
            }
        }
        
        logUtmInFirebase()
    }
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        if let fcmToken = fcmToken {
            DEBUG_LOG("fcmToken: \(fcmToken)")
            UserDefaults.set(fcmToken, forKey: .pushToken)
        }
    }
}

extension AppDelegate : UNUserNotificationCenterDelegate {
    
    // Receive displayed notifications for iOS 10 devices.
    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)
        
        Notifly.userNotificationCenter(center, willPresent: notification, withCompletionHandler: completionHandler)
        
        // ...
        
        // Print full message.
        DEBUG_LOG("userInfo: \(userInfo)")
        
        // Change this to your preferred presentation option
        completionHandler([.banner, .badge, .sound])
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        
        // With swizzling disabled you must let Messaging know about the message, for Analytics
        Messaging.messaging().appDidReceiveMessage(userInfo)
        Notifly.userNotificationCenter(center, didReceive: response)
        
        let roomIdString = userInfo["room_id"] as? String
        let contentIdString = userInfo["content_id"] as? String
        let channelIdString = userInfo["channel_id"] as? String
        let messageIdString = userInfo["message_id"] as? String
        let auditionIdString = userInfo["audition_id"] as? String
        
        if let roomIdString = roomIdString, let roomId = Int(roomIdString), roomId > 0 {
            AppState.shared.pushRoomId = roomId
        }
        
        if let contentIdString = contentIdString, let audioContentId = Int(contentIdString), audioContentId > 0 {
            AppState.shared.pushAudioContentId = audioContentId
        }
        
        if let channelIdString = channelIdString, let channelId = Int(channelIdString), channelId > 0 {
            AppState.shared.pushChannelId = channelId
        }
        
        if let messageIdString = messageIdString, let messageId = Int(messageIdString), messageId > 0 {
            AppState.shared.pushMessageId = messageId
        }
        
        if let auditionIdString = auditionIdString, let auditionId = Int(auditionIdString), auditionId > 0 {
            AppState.shared.startTab = .audition
            NotificationCenter.default.post(name: .didReceiveHomeTab, object: HomeViewModel.CurrentTab.audition)
        }
        
        completionHandler()
    }
}

extension Notification.Name {
    static let pointGranted = Notification.Name("POINT_GRANTED")
    static let didReceiveHomeTab = Notification.Name("didReceiveHomeTab")
}
