import APIClient
import AppIntents
import BrazeKit
import ComposableArchitecture
import Dependencies
import FeatureApp
import FeatureSettings
import InAppNotificationClient
import os.log
import SwiftData
@preconcurrency import SwiftUI
import UserDefaultsClient
import UserNotificationsClient
import Utilities

final class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    private let log = Logger(category: "AppDelegate")

    let store = Store(initialState: AppCoordinator.State()) {
        AppCoordinator()
    }

    // MARK: - Application delegate

    func application(_ application: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        log.info("didFinishLaunchingWithOptions")
        store.send(.appDelegate(.didFinishLaunching))
        log.info("Root TCA store finished `didFinishLaunching` action")

        /// This delegate needs to be set before `didFinishLaunchingWithOptions` returns
        /// If not, the system doesn't forward our notification taps to the app delegate
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        center.setNotificationCategories(Braze.Notifications.categories)

        /// anything in `didFinishLaunchingWithOptions` is called syncronously, and before the first frame is drawn to the screen.
        /// detach whatever we can and do it in the background instead
        Task.detached(priority: .low) {
            await application.registerForRemoteNotifications()
            CreateShortcutsProvider.updateAppShortcutParameters()
        }
        return true
    }

    nonisolated func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @Sendable @escaping () -> Void) {
        Task {
            await store.send(.appDelegate(.userNotifications(.didReceiveResponse(response, completionHandler: completionHandler))))
        }
    }

    nonisolated func userNotificationCenter(_: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @Sendable @escaping (UNNotificationPresentationOptions) -> Void) {
        Task {
            await store.send(.appDelegate(.userNotifications(.willPresentNotification(notification, completionHandler: completionHandler))))
        }
    }

    func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        store.send(.appDelegate(.didRegisterForRemoteNotifications(.success(deviceToken))))
    }

    func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        store.send(.appDelegate(.didRegisterForRemoteNotifications(.failure(error))))
    }

    func application(_: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        store.send(.appDelegate(.didReceiveRemoteNotification(userInfo: userInfo, completionHandler: completionHandler)))
    }

    func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        store.send(.appDelegate(.continueUserActivity(userActivity)))
        return true
    }

    /// NOTE: it doesn't seem like this function ever gets called on opening a URL.
    /// `func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool`
    /// it seems like apps opted into the SwiftUI app lifecycle don't get this. instead, they are supposed to use `View.onOpenURL`
}

@main
struct sunoApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @Shared(.appStorage(.appearanceMode)) var appearanceMode: AppearanceMode = .system

    var body: some Scene {
        WindowGroup {
            AppCoordinatorScreen(store: appDelegate.store)
                .onAppear {
                    // Apply saved appearance mode
                    guard let window = UIWindow.current else { return }

                    switch appearanceMode {
                    case .system:
                        window.overrideUserInterfaceStyle = .unspecified
                    case .light:
                        window.overrideUserInterfaceStyle = .light
                    case .dark:
                        window.overrideUserInterfaceStyle = .dark
                    }
                }
                /// https://stackoverflow.com/a/64035318 the SwiftUI app delegate adaptor doesn't support the `UIApplicationDelegate.applicationDidBecomeActive(_:)` method
                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
                    appDelegate.store.send(.appDelegate(.didBecomeActive))
                }
                .onOpenURL {
                    appDelegate.store.send(.appDelegate(.onOpenURL($0)))
                }
        }
    }
}
