import SwiftUI
import ComposeApp
import WidgetKit

@main
struct iOSApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @StateObject private var themeManager = ThemeManager.shared
    @StateObject private var contractorSharingManager = ContractorSharingManager.shared
    @StateObject private var residenceSharingManager = ResidenceSharingManager.shared
    @Environment(\.scenePhase) private var scenePhase
    @State private var deepLinkResetToken: String?
    /// Tracks foreground refresh tasks so they can be cancelled on subsequent transitions
    @State private var foregroundTask: Task<Void, Never>?
    @State private var pendingImportURL: URL?
    @State private var pendingImportType: HoneyDuePackageType = .contractor
    @State private var showImportConfirmation: Bool = false

    /// Type of honeydue package being imported
    enum HoneyDuePackageType {
        case contractor
        case residence
    }

    init() {
        UITestRuntime.configureForLaunch()

        // Set Keychain delegate BEFORE DataManager.initialize() so token can be
        // loaded from Keychain on startup (Kotlin/Native can't use SecItem* directly)
        TokenManager.Companion.shared.keychainDelegate = KeychainHelper.shared

        // Initialize DataManager with platform-specific managers
        // This must be done before any other operations that access DataManager
        DataManager.shared.initialize(
            tokenMgr: TokenManager.Companion.shared.getInstance(),
            themeMgr: ThemeStorageManager.Companion.shared.getInstance(),
            persistenceMgr: PersistenceManager()
        )

        // Reset state synchronously BEFORE AuthenticationManager reads auth status.
        // Using Task { @MainActor } here causes a race condition where
        // checkAuthenticationStatus() may run before resetState clears the token,
        // resulting in the app navigating to main tabs instead of the login screen.
        if UITestRuntime.isEnabled && UITestRuntime.shouldResetState {
            DataManager.shared.clear()
            OnboardingState.shared.reset()
            // Set flag directly — completeOnboarding() has an auth guard that
            // fails here because DataManager was just cleared (no token).
            if UITestRuntime.shouldCompleteOnboarding {
                OnboardingState.shared.hasCompletedOnboarding = true
            }
        }

        // Initialize TokenStorage once at app startup (legacy support)
        TokenStorage.shared.initialize(manager: TokenManager.Companion.shared.getInstance())

        if !UITestRuntime.isEnabled {
            // Initialize PostHog Analytics (must use Swift AnalyticsManager, not the Kotlin stub)
            AnalyticsManager.shared.configure()

            // Install uncaught exception handler to capture crashes to PostHog
            AnalyticsManager.shared.setupExceptionHandler()
        }
    }

    var body: some Scene {
        WindowGroup {
            RootView(deepLinkResetToken: $deepLinkResetToken)
                // Single source of truth injection — every descendant view can
                // reach @EnvironmentObject var dataManager: DataManagerObservable
                // without reading the .shared singleton implicitly.
                .environmentObject(DataManagerObservable.shared)
                .environmentObject(themeManager)
                .environmentObject(contractorSharingManager)
                .environmentObject(residenceSharingManager)
                .onOpenURL { url in
                    handleIncomingURL(url: url)
                }
                .onChange(of: scenePhase) { _, newPhase in
                    guard !UITestRuntime.isEnabled else { return }

                    if newPhase == .active {
                        // Sync auth token to widget if user is logged in
                        // This ensures widget has credentials even if user logged in before widget support was added
                        if let token = TokenStorage.shared.getToken() {
                            WidgetDataManager.shared.saveAuthToken(token)
                            WidgetDataManager.shared.saveAPIBaseURL(ApiClient.shared.getBaseUrl())
                        }

                        // Check and register device token when app becomes active
                        PushNotificationManager.shared.checkAndRegisterDeviceIfNeeded()

                        // Cancel any previous foreground refresh task before starting a new one
                        foregroundTask?.cancel()
                        foregroundTask = Task { @MainActor in
                            // Refresh lookups/static data
                            _ = try? await APILayer.shared.initializeLookups()

                            // Process any pending widget actions (task completions, mark in-progress)
                            WidgetActionProcessor.shared.processPendingActions()

                            // Check if widget completed a task - refresh data globally
                            if WidgetDataManager.shared.areTasksDirty() {
                                WidgetDataManager.shared.clearDirtyFlag()
                                let result = try? await APILayer.shared.getTasks(forceRefresh: true)
                                if let success = result as? ApiResultSuccess<TaskColumnsResponse>,
                                   let data = success.data {
                                    WidgetDataManager.shared.saveTasks(from: data)
                                }
                            }
                        }
                    } else if newPhase == .background {
                        // Refresh widget when app goes to background
                        WidgetCenter.shared.reloadAllTimelines()

                        // Schedule overnight background refresh (12am-4am)
                        BackgroundTaskManager.shared.scheduleAppRefresh()
                    }
                }
                // Import confirmation dialog - routes to appropriate handler
                .alert(importConfirmationTitle, isPresented: $showImportConfirmation) {
                    Button("Import") {
                        if let url = pendingImportURL {
                            switch pendingImportType {
                            case .contractor:
                                contractorSharingManager.importContractor(from: url) { _ in
                                    pendingImportURL = nil
                                }
                            case .residence:
                                residenceSharingManager.importResidence(from: url) { _ in
                                    pendingImportURL = nil
                                }
                            }
                        }
                    }
                    Button("Cancel", role: .cancel) {
                        pendingImportURL = nil
                    }
                } message: {
                    Text(importConfirmationMessage)
                }
                // Contractor import success dialog
                .alert("Contractor Imported", isPresented: $contractorSharingManager.importSuccess) {
                    Button("OK") {
                        contractorSharingManager.resetImportState()
                    }
                } message: {
                    Text("\(contractorSharingManager.importedContractorName ?? "Contractor") has been added to your contacts.")
                }
                // Contractor import error dialog
                .alert("Import Failed", isPresented: .init(
                    get: { contractorSharingManager.importError != nil },
                    set: { if !$0 { contractorSharingManager.resetImportState() } }
                )) {
                    Button("OK") {
                        contractorSharingManager.resetImportState()
                    }
                } message: {
                    Text(contractorSharingManager.importError ?? "An error occurred while importing the contractor.")
                }
                // Residence import success dialog
                .alert("Joined Residence", isPresented: $residenceSharingManager.importSuccess) {
                    Button("OK") {
                        residenceSharingManager.resetState()
                    }
                } message: {
                    Text("You now have access to \(residenceSharingManager.importedResidenceName ?? "the residence").")
                }
                // Residence import error dialog
                .alert("Join Failed", isPresented: .init(
                    get: { residenceSharingManager.errorMessage != nil && !residenceSharingManager.isImporting },
                    set: { if !$0 { residenceSharingManager.resetState() } }
                )) {
                    Button("OK") {
                        residenceSharingManager.resetState()
                    }
                } message: {
                    Text(residenceSharingManager.errorMessage ?? "An error occurred while joining the residence.")
                }
        }
    }

    // MARK: - Import Dialog Helpers

    private var importConfirmationTitle: String {
        switch pendingImportType {
        case .contractor:
            return "Import Contractor"
        case .residence:
            return "Join Residence"
        }
    }

    private var importConfirmationMessage: String {
        switch pendingImportType {
        case .contractor:
            return "Would you like to import this contractor to your contacts?"
        case .residence:
            return "Would you like to join this shared residence?"
        }
    }

    // MARK: - URL Handling

    /// Handles all incoming URLs - both deep links and file opens
    private func handleIncomingURL(url: URL) {
        #if DEBUG
        print("URL received: \(url)")
        #endif

        // Handle .honeydue file imports
        if url.pathExtension.lowercased() == "honeydue" {
            handleHoneyDueFileImport(url: url)
            return
        }

        // Handle honeydue:// deep links
        if url.scheme == "honeydue" {
            handleDeepLink(url: url)
            return
        }

        #if DEBUG
        print("Unrecognized URL: \(url)")
        #endif
    }

    /// Handles .honeydue file imports - detects type and routes accordingly
    private func handleHoneyDueFileImport(url: URL) {
        #if DEBUG
        print("honeyDue file received: \(url)")
        #endif

        // Check if user is authenticated
        guard TokenStorage.shared.getToken() != nil else {
            contractorSharingManager.importError = "You must be logged in to import"
            return
        }

        // Read file and detect type — copy to temp while security scope is active
        let accessing = url.startAccessingSecurityScopedResource()

        do {
            let data = try Data(contentsOf: url)

            // Copy to temp location so import works after security scope ends
            let tempURL = FileManager.default.temporaryDirectory
                .appendingPathComponent(UUID().uuidString)
                .appendingPathExtension("honeydue")
            try data.write(to: tempURL)

            do {
                if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
                   let typeString = json["type"] as? String {
                    pendingImportType = typeString == "residence" ? .residence : .contractor
                } else {
                    print("iOSApp: honeyDue file is valid JSON but missing 'type' field, defaulting to contractor")
                    pendingImportType = .contractor
                }
            } catch {
                print("iOSApp: Failed to parse honeydue file JSON: \(error)")
                if accessing {
                    url.stopAccessingSecurityScopedResource()
                }
                contractorSharingManager.importError = "The file appears to be corrupted and could not be read."
                return
            }

            pendingImportURL = tempURL
        } catch {
            #if DEBUG
            print("Failed to read honeydue file: \(error)")
            #endif
            pendingImportType = .contractor
            pendingImportURL = url
        }

        if accessing {
            url.stopAccessingSecurityScopedResource()
        }

        showImportConfirmation = true
    }

    /// Handles honeydue:// deep links
    private func handleDeepLink(url: URL) {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return }
        let host = url.host

        switch host {
        case "reset-password":
            if let token = components.queryItems?.first(where: { $0.name == "token" })?.value {
                #if DEBUG
                print("Reset token extracted: \(token)")
                #endif
                deepLinkResetToken = token
            }
        case "task":
            if let idString = components.queryItems?.first(where: { $0.name == "id" })?.value,
               let id = Int(idString) {
                NotificationCenter.default.post(name: .navigateToTask, object: nil, userInfo: ["taskId": id])
            }
        case "residence":
            if let idString = components.queryItems?.first(where: { $0.name == "id" })?.value,
               let id = Int(idString) {
                NotificationCenter.default.post(name: .navigateToResidence, object: nil, userInfo: ["residenceId": id])
            }
        case "document":
            if let idString = components.queryItems?.first(where: { $0.name == "id" })?.value,
               let id = Int(idString) {
                NotificationCenter.default.post(name: .navigateToDocument, object: nil, userInfo: ["documentId": id])
            }
        default:
            #if DEBUG
            print("Unrecognized deep link host: \(host ?? "nil")")
            #endif
        }
    }
}
