//
//  BackgroundTaskManager.swift
//  iosApp
//
//  Manages background task scheduling for overnight task data refresh.
//  Runs at a random time between 12:00 AM and 4:00 AM local time.
//

import Foundation
import BackgroundTasks
import WidgetKit
import ComposeApp

/// Manages background app refresh to keep task data fresh overnight
final class BackgroundTaskManager {
    static let shared = BackgroundTaskManager()

    /// Background task identifier - must match Info.plist BGTaskSchedulerPermittedIdentifiers
    static let taskIdentifier = "com.tt.honeyDue.refresh"

    /// Time window for overnight refresh (12:00 AM - 4:00 AM)
    private let refreshWindowStartHour = 0  // 12:00 AM
    private let refreshWindowEndHour = 4    // 4:00 AM

    private init() {}

    // MARK: - Registration

    /// Register background tasks with the system. Call this in AppDelegate didFinishLaunchingWithOptions.
    func registerBackgroundTasks() {
        BGTaskScheduler.shared.register(
            forTaskWithIdentifier: Self.taskIdentifier,
            using: nil
        ) { [weak self] task in
            guard let bgTask = task as? BGAppRefreshTask else { return }
            self?.handleAppRefresh(task: bgTask)
        }
        print("BackgroundTaskManager: Registered background task \(Self.taskIdentifier)")
    }

    // MARK: - Scheduling

    /// Schedule the next background refresh. Call this when the app goes to background.
    func scheduleAppRefresh() {
        let request = BGAppRefreshTaskRequest(identifier: Self.taskIdentifier)

        // Calculate a random time between 12:00 AM and 4:00 AM
        request.earliestBeginDate = calculateNextRefreshDate()

        do {
            try BGTaskScheduler.shared.submit(request)
            print("BackgroundTaskManager: Scheduled background refresh for \(request.earliestBeginDate?.description ?? "unknown")")
        } catch {
            print("BackgroundTaskManager: Failed to schedule background refresh - \(error.localizedDescription)")
        }
    }

    /// Cancel any pending background refresh requests
    func cancelPendingRefresh() {
        BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: Self.taskIdentifier)
        print("BackgroundTaskManager: Cancelled pending background refresh")
    }

    // MARK: - Task Handling

    /// Handle the background app refresh task
    private func handleAppRefresh(task: BGAppRefreshTask) {
        print("BackgroundTaskManager: Starting background refresh at \(Date())")

        // Schedule the next refresh before we start (in case this one fails)
        scheduleAppRefresh()

        // Create a task to fetch data
        let refreshTask = Task {
            await performDataRefresh()
        }

        // Set up expiration handler
        task.expirationHandler = {
            print("BackgroundTaskManager: Task expired, cancelling")
            refreshTask.cancel()
        }

        // Wait for the refresh to complete
        Task {
            let success = await refreshTask.value
            task.setTaskCompleted(success: success)
            print("BackgroundTaskManager: Background refresh completed with success=\(success)")
        }
    }

    /// Perform the actual data refresh
    private func performDataRefresh() async -> Bool {
        // Check if user is authenticated
        guard let token = TokenStorage.shared.getToken(), !token.isEmpty else {
            print("BackgroundTaskManager: No auth token, skipping refresh")
            return true // Not a failure, just nothing to do
        }

        do {
            // Fetch tasks from API
            print("BackgroundTaskManager: Fetching tasks from API...")
            let result = try await APILayer.shared.getTasks(forceRefresh: true)

            if let success = result as? ApiResultSuccess<TaskColumnsResponse>,
               let data = success.data {
                // Write to DataManager (memory) - this happens automatically in APILayer
                print("BackgroundTaskManager: Tasks loaded into DataManager")

                // Write to shared App Group for widget
                WidgetDataManager.shared.saveTasks(from: data)
                print("BackgroundTaskManager: Tasks saved to shared App Group")

                // Update widget
                WidgetCenter.shared.reloadAllTimelines()
                print("BackgroundTaskManager: Widget timelines reloaded")

                return true
            } else if let error = ApiResultBridge.error(from: result) {
                print("BackgroundTaskManager: API error - \(error.message)")
                return false
            }

            print("BackgroundTaskManager: Unexpected API result type during refresh")
            return false
        } catch {
            print("BackgroundTaskManager: Error during refresh - \(error.localizedDescription)")
            return false
        }
    }

    // MARK: - Time Calculation

    /// Calculate the next refresh date (random time between 12:00 AM and 4:00 AM)
    private func calculateNextRefreshDate() -> Date {
        let calendar = Calendar.current
        let now = Date()

        // Get today's date components
        var components = calendar.dateComponents([.year, .month, .day], from: now)

        // Determine if we should schedule for tonight or tomorrow night
        let currentHour = calendar.component(.hour, from: now)

        // If it's already past midnight (past the refresh window), schedule for tomorrow night
        if currentHour >= refreshWindowEndHour {
            // Add one day to schedule for tomorrow's window
            if let tomorrow = calendar.date(byAdding: .day, value: 1, to: now) {
                components = calendar.dateComponents([.year, .month, .day], from: tomorrow)
            }
        }

        // Generate random hour (0-3) and minute (0-59) within the refresh window
        let randomHour = Int.random(in: refreshWindowStartHour..<refreshWindowEndHour)
        let randomMinute = Int.random(in: 0..<60)
        let randomSecond = Int.random(in: 0..<60)

        components.hour = randomHour
        components.minute = randomMinute
        components.second = randomSecond

        // Create the scheduled date
        if let scheduledDate = calendar.date(from: components) {
            // Make sure it's in the future
            if scheduledDate > now {
                return scheduledDate
            } else {
                // If somehow in the past, add a day
                return calendar.date(byAdding: .day, value: 1, to: scheduledDate) ?? scheduledDate
            }
        }

        // Fallback: schedule for 2 hours from now
        return now.addingTimeInterval(2 * 60 * 60)
    }

    // MARK: - Debug Helpers

    /// Get a description of the current scheduling state (for debugging)
    func getSchedulingStatus() -> String {
        let nextDate = calculateNextRefreshDate()
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .short
        return "Next refresh scheduled for approximately: \(formatter.string(from: nextDate))"
    }

    /// Force a background refresh for testing (only works in debug builds with Xcode)
    /// Usage: In Xcode debugger console:
    /// e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.tt.honeyDue.refresh"]
    func debugInfo() -> String {
        return """
        Background Task Debug Info:
        - Task ID: \(Self.taskIdentifier)
        - Refresh Window: \(refreshWindowStartHour):00 - \(refreshWindowEndHour):00
        - \(getSchedulingStatus())

        To test in Xcode debugger:
        e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"\(Self.taskIdentifier)"]
        """
    }
}
