import BackgroundTasks
import UIKit

// 后台续传（iOS 26 BGContinuedProcessingTask）。前台发起的传输切到后台时，向系统申请续跑
// 任务并展示系统进度 UI（类比 AirDrop）。任务生命周期绑定活跃传输集合：0→>0（且前台）时
// 提交、随字节更新 progress、回到 0 时完成。
//
// 真机验证点（R-iOS-3）：BGContinuedProcessingTask 给「应用」后台运行时间 + 系统进度 UI，
// 但承载传输的 WKWebView 是独立 WebContent 进程，其 JS / WebRTC 是否随之保活须真机验；若仍
// 被挂起，行为退化为「切后台暂停、回前台续传」（R-iOS-1 允许，文件传输本需前台）。
//
// 全程主线程驱动：register 用 .main 队列、sync 由引擎主线程回调触发，故不引入 actor 隔离。
final class BackgroundTaskManager
{
    static let shared = BackgroundTaskManager()
    private init() {}

    // 标识符通配前缀。Info.plist 的 BGTaskSchedulerPermittedIdentifiers 须含 "<prefix>.*"，
    // 否则注册返回 false、提交抛错——届时仅退化为不申请后台续跑，传输逻辑不受影响。
    private static let prefix = "net.commilitia.Commilitia-Drop.transfer"
    private static let wildcard = prefix + ".*"

    private var triedRegister = false
    private var registerOK = false
    private var task: BGContinuedProcessingTask?
    private var pendingId: String?       // 已提交、尚未 attach 的请求标识符（用于回到 0 时取消）。
    private var latestFraction: Double = 0

    // 应用启动时注册一次（须在 launch 完成前——由 AppDelegate.didFinishLaunching 调用）。
    func registerOnce()
    {
        guard !triedRegister else { return }
        triedRegister = true
        registerOK = BGTaskScheduler.shared.register(
            forTaskWithIdentifier: Self.wildcard, using: .main)
        { [weak self] task in
            guard let cpt = task as? BGContinuedProcessingTask
            else { task.setTaskCompleted(success: false); return }
            self?.attach(cpt)
        }
    }

    // 引擎每次刷新活跃传输时调用：activeCount 活跃传输数，fraction 总进度 [0, 1]。
    func sync(activeCount: Int, fraction: Double)
    {
        latestFraction = fraction
        if activeCount > 0
        {
            if let task { task.progress.completedUnitCount = Int64(fraction * 100) }
            else { submitIfForeground() }
        }
        else
        {
            finish(success: true)
        }
    }

    private func submitIfForeground()
    {
        // 注册失败（未声明权限）/ 已在运行 / 已提交待 attach：均不再提交。
        guard registerOK, task == nil, pendingId == nil else { return }
        // 系统拒绝后台提交（且传输入口本就在前台），故仅前台提交。
        guard UIApplication.shared.applicationState != .background else { return }

        let id = "\(Self.prefix).\(UUID().uuidString.prefix(8))"
        let request = BGContinuedProcessingTaskRequest(
            identifier: id, title: t("ios.bg.title"), subtitle: t("ios.bg.subtitle"))
        request.strategy = .queue
        do
        {
            try BGTaskScheduler.shared.submit(request)
            pendingId = id
        }
        catch
        {
            // 提交失败（无空位 / 系统负载高）：传输仍在前台正常跑，非致命。
        }
    }

    private func attach(_ task: BGContinuedProcessingTask)
    {
        pendingId = nil
        self.task = task
        task.progress.totalUnitCount = 100
        task.progress.completedUnitCount = Int64(latestFraction * 100)
        task.expirationHandler = { [weak self] in
            self?.task?.setTaskCompleted(success: false)
            self?.task = nil
        }
    }

    private func finish(success: Bool)
    {
        if let task
        {
            task.progress.completedUnitCount = task.progress.totalUnitCount
            task.setTaskCompleted(success: success)
            self.task = nil
        }
        if let pendingId
        {
            BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: pendingId)
            self.pendingId = nil
        }
    }
}
