//
//  SportsTimeApp.swift
//  SportsTime
//
//  Created by Trey Tartt on 1/6/26.
//

import SwiftUI
import SwiftData
import BackgroundTasks
import CloudKit

@main
struct SportsTimeApp: App {
    /// App delegate for handling push notifications
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    /// Task that listens for StoreKit transaction updates
    private var transactionListener: Task<Void, Never>?

    init() {
        // Configure sync manager immediately so push/background triggers can sync.
        BackgroundSyncManager.shared.configure(with: sharedModelContainer)

        // Register background tasks BEFORE app finishes launching
        // This must happen synchronously in init or applicationDidFinishLaunching
        BackgroundSyncManager.shared.registerTasks()

        // Start listening for transactions immediately
        transactionListener = StoreManager.shared.listenForTransactions()
    }

    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            // User data models
            SavedTrip.self,
            TripVote.self,
            UserPreferences.self,
            CachedSchedule.self,
            // Stadium progress models
            StadiumVisit.self,
            VisitPhotoMetadata.self,
            Achievement.self,
            CachedGameScore.self,
            // Poll models
            LocalTripPoll.self,
            LocalPollVote.self,
            // Canonical data models
            SyncState.self,
            CanonicalStadium.self,
            StadiumAlias.self,
            CanonicalTeam.self,
            TeamAlias.self,
            LeagueStructureModel.self,
            CanonicalGame.self,
            CanonicalSport.self,
        ])
        let modelConfiguration = ModelConfiguration(
            schema: schema,
            isStoredInMemoryOnly: false,
            cloudKitDatabase: .none  // Local only; CloudKit used separately for schedules
        )

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            BootstrappedContentView(modelContainer: sharedModelContainer)
                .environment(\.isDemoMode, ProcessInfo.isDemoMode)
        }
        .modelContainer(sharedModelContainer)
    }
}

// MARK: - Bootstrapped Content View

/// Wraps the main content with bootstrap logic.
/// Shows a loading indicator until bootstrap completes, then shows HomeView.
struct BootstrappedContentView: View {
    let modelContainer: ModelContainer

    @Environment(\.scenePhase) private var scenePhase
    @State private var isBootstrapping = true
    @State private var bootstrapError: Error?
    @State private var hasCompletedInitialSync = false
    @State private var showOnboardingPaywall = false
    @State private var deepLinkHandler = DeepLinkHandler.shared
    @State private var appearanceManager = AppearanceManager.shared

    private var shouldShowOnboardingPaywall: Bool {
        !UserDefaults.standard.bool(forKey: "hasSeenOnboardingPaywall") && !StoreManager.shared.isPro
    }

    var body: some View {
        Group {
            if isBootstrapping {
                BootstrapLoadingView()
            } else if let error = bootstrapError {
                BootstrapErrorView(error: error) {
                    Task {
                        await performBootstrap()
                    }
                }
            } else {
                HomeView()
                    .sheet(isPresented: $showOnboardingPaywall) {
                        OnboardingPaywallView(isPresented: $showOnboardingPaywall)
                            .interactiveDismissDisabled()
                    }
                    .sheet(item: $deepLinkHandler.pendingPollShareCode) { code in
                        NavigationStack {
                            PollDetailView(shareCode: code)
                        }
                    }
                    .alert("Error", isPresented: .constant(deepLinkHandler.error != nil)) {
                        Button("OK") { deepLinkHandler.clearPending() }
                    } message: {
                        Text(deepLinkHandler.error?.localizedDescription ?? "")
                    }
                    .onAppear {
                        if shouldShowOnboardingPaywall {
                            showOnboardingPaywall = true
                        }
                    }
            }
        }
        .task {
            await performBootstrap()
        }
        .onOpenURL { url in
            deepLinkHandler.handleURL(url)
        }
        .onChange(of: scenePhase) { _, newPhase in
            switch newPhase {
            case .active:
                // Refresh super properties (subscription status may have changed)
                AnalyticsManager.shared.updateSuperProperties()
                // Track subscription state with rich properties for funnel analysis
                StoreManager.shared.trackSubscriptionAnalytics(source: "app_foreground")
                // Sync when app comes to foreground (but not on initial launch)
                if hasCompletedInitialSync {
                    Task {
                        await performBackgroundSync(context: modelContainer.mainContext)
                    }
                }
            case .background:
                // Flush pending analytics events
                AnalyticsManager.shared.flush()
                // Schedule background tasks when app goes to background
                BackgroundSyncManager.shared.scheduleAllTasks()
            default:
                break
            }
        }
        .preferredColorScheme(appearanceManager.currentMode.colorScheme)
    }

    @MainActor
    private func performBootstrap() async {
        print("🚀 [BOOT] Starting app bootstrap...")
        isBootstrapping = true
        bootstrapError = nil

        let context = modelContainer.mainContext
        let bootstrapService = BootstrapService()

        do {
            // 1. Bootstrap from bundled JSON if first launch (no data exists)
            print("🚀 [BOOT] Step 1: Checking if bootstrap needed...")
            try await bootstrapService.bootstrapIfNeeded(context: context)

            // 2. Configure DataProvider with SwiftData context
            print("🚀 [BOOT] Step 2: Configuring DataProvider...")
            AppDataProvider.shared.configure(with: context)

            // 3. Configure BackgroundSyncManager with model container
            print("🚀 [BOOT] Step 3: Configuring BackgroundSyncManager...")
            BackgroundSyncManager.shared.configure(with: modelContainer)

            // 4. Load data from SwiftData into memory
            print("🚀 [BOOT] Step 4: Loading initial data from SwiftData...")
            await AppDataProvider.shared.loadInitialData()
            if let loadError = AppDataProvider.shared.error {
                throw loadError
            }
            print("🚀 [BOOT]   Loaded \(AppDataProvider.shared.teams.count) teams")
            print("🚀 [BOOT]   Loaded \(AppDataProvider.shared.stadiums.count) stadiums")

            // 5. Load store products and entitlements
            print("🚀 [BOOT] Step 5: Loading store products...")
            await StoreManager.shared.loadProducts()
            await StoreManager.shared.updateEntitlements()

            // 6. Start network monitoring and wire up sync callback
            print("🚀 [BOOT] Step 6: Starting network monitoring...")
            NetworkMonitor.shared.onSyncNeeded = {
                await BackgroundSyncManager.shared.triggerSyncFromNetworkRestoration()
            }
            NetworkMonitor.shared.startMonitoring()

            // 7. Configure analytics
            print("🚀 [BOOT] Step 7: Configuring analytics...")
            AnalyticsManager.shared.configure()

            // 8. App is now usable
            print("🚀 [BOOT] Step 8: Bootstrap complete - app ready")
            isBootstrapping = false

            // 9. Schedule background tasks for future syncs
            BackgroundSyncManager.shared.scheduleAllTasks()

            // 9b. Ensure CloudKit subscriptions exist for push-driven sync.
            Task(priority: .utility) {
                await BackgroundSyncManager.shared.ensureCanonicalSubscriptions()
            }

            // 10. Background: Try to refresh from CloudKit (non-blocking)
            print("🚀 [BOOT] Step 10: Starting background CloudKit sync...")
            Task(priority: .background) {
                await self.performBackgroundSync(context: self.modelContainer.mainContext)
                await MainActor.run {
                    self.hasCompletedInitialSync = true
                }
            }
        } catch {
            print("❌ [BOOT] Bootstrap failed: \(error.localizedDescription)")
            bootstrapError = error
            isBootstrapping = false
        }
    }

    @MainActor
    private func performBackgroundSync(context: ModelContext) async {
        let log = SyncLogger.shared
        log.log("🔄 [SYNC] Starting background sync...")
        AccessibilityAnnouncer.announce("Sync started.")

        // Log diagnostic info for debugging CloudKit container issues
        let bundleId = Bundle.main.bundleIdentifier ?? "unknown"
        let container = CloudKitContainerConfig.makeContainer()
        let containerId = container.containerIdentifier ?? "unknown"
        log.log("🔧 [DIAG] Bundle ID: \(bundleId)")
        log.log("🔧 [DIAG] CloudKit container: \(containerId)")
        log.log("🔧 [DIAG] Configured container: \(CloudKitContainerConfig.identifier)")
        if let accountStatus = try? await container.accountStatus() {
            log.log("🔧 [DIAG] iCloud account status: \(accountStatus.rawValue) (0=couldNotDetermine, 1=available, 2=restricted, 3=noAccount)")
        } else {
            log.log("🔧 [DIAG] iCloud account status: failed to check")
        }

        // Only reset stale syncInProgress flags; do not clobber an actively running sync.
        let syncState = SyncState.current(in: context)
        if syncState.syncInProgress {
            let staleSyncTimeout: TimeInterval = 15 * 60
            if let lastAttempt = syncState.lastSyncAttempt,
               Date().timeIntervalSince(lastAttempt) < staleSyncTimeout {
                log.log("ℹ️ [SYNC] Sync already in progress; skipping duplicate trigger")
                return
            }

            log.log("⚠️ [SYNC] Resetting stale syncInProgress flag")
            syncState.syncInProgress = false
            try? context.save()
        }

        let syncService = CanonicalSyncService()

        do {
            let result = try await syncService.syncAll(context: context)

            log.log("🔄 [SYNC] Sync completed in \(String(format: "%.2f", result.duration))s")
            log.log("🔄 [SYNC]   Stadiums: \(result.stadiumsUpdated)")
            log.log("🔄 [SYNC]   Teams: \(result.teamsUpdated)")
            log.log("🔄 [SYNC]   Games: \(result.gamesUpdated)")
            log.log("🔄 [SYNC]   League Structures: \(result.leagueStructuresUpdated)")
            log.log("🔄 [SYNC]   Team Aliases: \(result.teamAliasesUpdated)")
            log.log("🔄 [SYNC]   Stadium Aliases: \(result.stadiumAliasesUpdated)")
            log.log("🔄 [SYNC]   Sports: \(result.sportsUpdated)")
            log.log("🔄 [SYNC]   Skipped (incompatible): \(result.skippedIncompatible)")
            log.log("🔄 [SYNC]   Skipped (older): \(result.skippedOlder)")
            log.log("🔄 [SYNC]   Total updated: \(result.totalUpdated)")

            // If any data was updated, reload the DataProvider
            if !result.isEmpty {
                log.log("🔄 [SYNC] Reloading DataProvider...")
                await AppDataProvider.shared.loadInitialData()
                log.log("🔄 [SYNC] DataProvider reloaded. Teams: \(AppDataProvider.shared.teams.count), Stadiums: \(AppDataProvider.shared.stadiums.count)")
            } else {
                log.log("🔄 [SYNC] No updates - skipping DataProvider reload")
            }
            AccessibilityAnnouncer.announce("Sync complete. Updated \(result.totalUpdated) records.")
        } catch CanonicalSyncService.SyncError.cloudKitUnavailable {
            log.log("❌ [SYNC] CloudKit unavailable - using local data only")
            AccessibilityAnnouncer.announce("Cloud sync unavailable. Using local data.")
        } catch {
            log.log("❌ [SYNC] Error: \(error.localizedDescription)")
            AccessibilityAnnouncer.announce("Sync failed. \(error.localizedDescription)")
        }
    }

}

// MARK: - String Identifiable for Sheet

extension String: @retroactive Identifiable {
    public var id: String { self }
}

// MARK: - Bootstrap Loading View

struct BootstrapLoadingView: View {
    var body: some View {
        VStack(spacing: 20) {
            LoadingSpinner(size: .large)

            Text("Setting up SportsTime...")
                .font(.headline)
                .foregroundStyle(.secondary)
        }
    }
}

// MARK: - Bootstrap Error View

struct BootstrapErrorView: View {
    let error: Error
    let onRetry: () -> Void

    var body: some View {
        VStack(spacing: 20) {
            Image(systemName: "exclamationmark.triangle.fill")
                .font(.system(size: 50))
                .foregroundStyle(.orange)

            Text("Setup Failed")
                .font(.title2)
                .fontWeight(.semibold)

            Text(error.localizedDescription)
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
                .padding(.horizontal)

            Button("Try Again") {
                onRetry()
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
