import UIKit
import Capacitor
import BackgroundTasks
import DailyNotificationPlugin
import ObjectiveC
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        NSLog("DNP-DEBUG: AppDelegate.application(_:didFinishLaunchingWithOptions:) called")
        
        // DIAGNOSTIC: Test plugin class accessibility via Objective-C runtime
        NSLog("DNP-DEBUG: Testing plugin class accessibility...")
        
        // Test 1: NSClassFromString (Objective-C runtime lookup)
        if let pluginClass = NSClassFromString("DailyNotificationPlugin") {
            NSLog("DNP-DEBUG: ✅ NSClassFromString found plugin class: %@", String(describing: pluginClass))
        } else {
            NSLog("DNP-DEBUG: ❌ NSClassFromString could NOT find plugin class 'DailyNotificationPlugin'")
        }
        
        // Test 2: Swift type access
        let pluginType = DailyNotificationPlugin.self
        NSLog("DNP-DEBUG: Plugin class type: %@", String(describing: pluginType))
        NSLog("DNP-DEBUG: Plugin class name: %@", String(describing: type(of: pluginType)))
        
        // Test 3: Verify CAPPlugin inheritance
        // Note: 'is' test is always true because DailyNotificationPlugin extends CAPPlugin
        NSLog("DNP-DEBUG: ✅ Plugin is a CAPPlugin subclass (DailyNotificationPlugin extends CAPPlugin)")
        
        // Test 4: Check if class conforms to NSObjectProtocol (required for Objective-C runtime)
        // Note: 'is' test is always true because CAPPlugin extends NSObject which conforms to NSObjectProtocol
        NSLog("DNP-DEBUG: ✅ Plugin conforms to NSObjectProtocol (CAPPlugin extends NSObject)")
        
        // Test 5: Try to get class name via Objective-C runtime
        let className = NSStringFromClass(pluginType)
        NSLog("DNP-DEBUG: Plugin class name (NSStringFromClass): %@", className)
        
        // Test 6: Check if framework is loaded
        if let framework = Bundle(identifier: "org.cocoapods.DailyNotificationPlugin") {
            NSLog("DNP-DEBUG: ✅ Plugin framework bundle found: %@", framework.bundlePath)
        } else {
            NSLog("DNP-DEBUG: ⚠️ Plugin framework bundle not found via identifier")
            // Try alternative: check if class is in main bundle
            if Bundle.main.path(forResource: "DailyNotificationPlugin", ofType: "framework") != nil {
                NSLog("DNP-DEBUG: ✅ Plugin framework found in main bundle")
            } else {
                NSLog("DNP-DEBUG: ⚠️ Plugin framework not found in main bundle")
            }
        }
        
        // CRITICAL: Force-load the plugin framework before Capacitor initializes
        // objc_getClassList may not include classes from frameworks that haven't been loaded yet
        // Even though NSClassFromString can find the class, Capacitor's discovery uses objc_getClassList
        // which only includes loaded classes. We need to ensure the framework is loaded.
        NSLog("DNP-DEBUG: Force-loading DailyNotificationPlugin framework...")
        _ = DailyNotificationPlugin.self  // Force class load
        NSLog("DNP-DEBUG: DailyNotificationPlugin class reference created - framework should be loaded")
        
        // Verify class is now in objc_getClassList
        let classCount = objc_getClassList(nil, 0)
        let classes = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(classCount))
        defer { classes.deallocate() }
        let releasingClasses = AutoreleasingUnsafeMutablePointer<AnyClass>(classes)
        let numClasses = objc_getClassList(releasingClasses, Int32(classCount))
        
        var foundInClassList = false
        for i in 0..<Int(numClasses) {
            if let aClass = classes[i] {
                let className = NSStringFromClass(aClass)
                if className == "DailyNotificationPlugin" {
                    foundInClassList = true
                    NSLog("DNP-DEBUG: ✅ DailyNotificationPlugin found in objc_getClassList")
                    break
                }
            }
        }
        if !foundInClassList {
            NSLog("DNP-DEBUG: ❌ DailyNotificationPlugin NOT found in objc_getClassList (this is the problem!)")
        } else {
            // Test if class conforms to CAPBridgedPlugin (required for Capacitor discovery)
            if let aClass = NSClassFromString("DailyNotificationPlugin") {
                // Try using CAPBridgedPlugin.self (the actual protocol, not string lookup)
                // This is what Capacitor uses: class_conformsToProtocol(aClass, CAPBridgedPlugin.self)
                let conformsToBridgedPlugin = class_conformsToProtocol(aClass, CAPBridgedPlugin.self)
                NSLog("DNP-DEBUG: Class conforms to CAPBridgedPlugin (using .self): %@", conformsToBridgedPlugin ? "YES" : "NO")
                
                // Test if class can be cast to CapacitorPlugin.Type
                if let pluginType = aClass as? CAPPlugin.Type {
                    // Try casting to CapacitorPlugin (which is CAPPlugin & CAPBridgedPlugin)
                    if pluginType is (CAPPlugin & CAPBridgedPlugin).Type {
                        NSLog("DNP-DEBUG: ✅ Can cast to (CAPPlugin & CAPBridgedPlugin).Type")
                    } else {
                        NSLog("DNP-DEBUG: ❌ Cannot cast to (CAPPlugin & CAPBridgedPlugin).Type")
                    }
                }
            }
        }
        
        // NOTE: Background task registration is handled by DailyNotificationPlugin.load()
        // Do NOT register here to avoid duplicate registration crash
        
        // Set notification center delegate to show notifications in foreground
        // Set immediately and also after Capacitor initializes to ensure it's always set
        UNUserNotificationCenter.current().delegate = self
        NSLog("DNP-DEBUG: UNUserNotificationCenter delegate set to AppDelegate (immediate)")
        
        // Also set after Capacitor initializes (in case it resets the delegate)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            UNUserNotificationCenter.current().delegate = self
            NSLog("DNP-DEBUG: UNUserNotificationCenter delegate re-set after Capacitor init")
        }
        
        // Override point for customization after application launch.
        return true
    }
    
    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.
        
        // Re-set delegate when app becomes active (in case Capacitor resets it)
        UNUserNotificationCenter.current().delegate = self
        NSLog("DNP-DEBUG: UNUserNotificationCenter delegate re-set in applicationDidBecomeActive")
    }
    
    // MARK: - UNUserNotificationCenterDelegate
    
    /**
     * Show notifications even when app is in foreground
     * This is required for test app to see notifications during testing
     */
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        NSLog("DNP-DEBUG: ✅ userNotificationCenter willPresent called!")
        NSLog("DNP-DEBUG: Notification received in foreground: %@", notification.request.identifier)
        NSLog("DNP-DEBUG: Notification title: %@", notification.request.content.title)
        NSLog("DNP-DEBUG: Notification body: %@", notification.request.content.body)
        NSLog("DNP-DEBUG: Current delegate: %@", UNUserNotificationCenter.current().delegate != nil ? "SET" : "NOT SET")
        
        // Extract notification info from userInfo for rollover
        let userInfo = notification.request.content.userInfo
        if let notificationId = userInfo["notification_id"] as? String,
           let scheduledTime = userInfo["scheduled_time"] as? Int64 {
            
            // Format scheduled time for logging
            let scheduledDate = Date(timeIntervalSince1970: Double(scheduledTime) / 1000.0)
            let formatter = DateFormatter()
            formatter.dateStyle = .medium
            formatter.timeStyle = .short
            let scheduledTimeStr = formatter.string(from: scheduledDate)
            
            NSLog("DNP-ROLLOVER: APPDELGATE_DETECTED id=%@ scheduled_time=%@", notificationId, scheduledTimeStr)
            NSLog("DNP-DEBUG: Posted rollover notification for id=%@", notificationId)
            
            // Post notification to trigger rollover (decoupled pattern)
            NotificationCenter.default.post(
                name: NSNotification.Name("DailyNotificationDelivered"),
                object: nil,
                userInfo: [
                    "notification_id": notificationId,
                    "scheduled_time": scheduledTime
                ]
            )
        } else {
            NSLog("DNP-ROLLOVER: APPDELGATE_MISSING_DATA id=%@ userInfo=%@", notification.request.identifier, userInfo)
        }
        
        // Show notification with banner, sound, and badge
        // Use .banner for iOS 14+, fallback to .alert for iOS 13
        if #available(iOS 14.0, *) {
            completionHandler([.banner, .sound, .badge])
        } else {
            completionHandler([.alert, .sound, .badge])
        }
        
        NSLog("DNP-DEBUG: ✅ Completion handler called with presentation options")
    }
    
    /**
     * Handle notification tap/interaction
     */
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        NSLog("DNP-DEBUG: Notification tapped: %@", response.notification.request.identifier)
        NSLog("DNP-DEBUG: Action identifier: %@", response.actionIdentifier)
        
        // Handle notification tap if needed
        // For test app, we just log it
        completionHandler()
    }

    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 applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
        // Called when the app was launched with a url. Feel free to add additional processing here,
        // but if you want the App API to support tracking app url opens, make sure to keep this call
        return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
    }

    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        // Called when the app was launched with an activity, including Universal Links.
        // Feel free to add additional processing here, but if you want the App API to support
        // tracking app url opens, make sure to keep this call
        return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
    }

}
