//
//  PushNotificationManager.swift
//  suixinkan
//
//  Created by Codex on 2026/6/26.
//

import UIKit
import UserNotifications

@MainActor
/// 推送生命周期管理器，负责权限、APNs 注册、token 上报和通知点击路由。
final class PushNotificationManager: NSObject, UNUserNotificationCenterDelegate {
    static let shared = PushNotificationManager()

    private var api: PushAPI?
    private weak var session: AppSession?
    private weak var router: AppRouter?
    private var latestDeviceToken: String?
    private var latestAuthorizationStatus: UNAuthorizationStatus = .notDetermined
    private let tokenDefaultsKey = "apns_device_token"
    private let uploadedTokenDefaultsKey = "apns_uploaded_token"

    override init() {
        super.init()
    }

    /// 绑定推送所需的网络、登录和导航依赖。
    func configure(api: PushAPI, session: AppSession, router: AppRouter) {
        self.api = api
        self.session = session
        self.router = router
        UNUserNotificationCenter.current().delegate = self
        latestDeviceToken = UserDefaults.standard.string(forKey: tokenDefaultsKey)
    }

    /// 请求通知权限并注册 APNs；已授权时会直接注册并尝试补传缓存 token。
    func requestAuthorizationAndRegister() {
        Task { @MainActor in
            let settings = await UNUserNotificationCenter.current().notificationSettings()
            latestAuthorizationStatus = settings.authorizationStatus
            switch settings.authorizationStatus {
            case .notDetermined:
                let granted = (try? await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound])) ?? false
                guard granted else { return }
                UIApplication.shared.registerForRemoteNotifications()
            case .authorized, .provisional, .ephemeral:
                UIApplication.shared.registerForRemoteNotifications()
                uploadPendingTokenIfPossible()
            case .denied:
                break
            @unknown default:
                break
            }
        }
    }

    /// 处理系统返回的 APNs token。
    func handleDeviceToken(_ deviceToken: Data) {
        let token = APNsDeviceToken.hexString(from: deviceToken)
        latestDeviceToken = token
        UserDefaults.standard.set(token, forKey: tokenDefaultsKey)
        uploadPendingTokenIfPossible()
    }

    /// 处理 APNs 注册失败。失败不阻断登录和主流程。
    func handleRegistrationError(_ error: Error) {
        #if DEBUG
        print("APNs registration failed: \(error.localizedDescription)")
        #endif
    }

    /// 登录后补传尚未成功上报的 token。
    func uploadPendingTokenIfPossible() {
        guard let api, session?.isLoggedIn == true else { return }
        guard let token = latestDeviceToken, !token.isEmpty else { return }
        let uploaded = UserDefaults.standard.string(forKey: uploadedTokenDefaultsKey)
        guard uploaded != token else { return }

        Task {
            do {
                try await api.registerJPushId(token)
                UserDefaults.standard.set(token, forKey: uploadedTokenDefaultsKey)
            } catch {
                #if DEBUG
                print("Push token upload failed: \(error.localizedDescription)")
                #endif
            }
        }
    }

    /// 处理静默或远程通知 userInfo。
    func handleRemoteNotification(_ userInfo: [AnyHashable: Any]) {
        route(from: PushPayload(userInfo: userInfo))
    }

    /// 处理已解析的推送 payload。供系统回调和单测复用。
    func handleRemoteNotification(_ payload: PushPayload) {
        route(from: payload)
    }

    nonisolated func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        let payload = PushPayload(userInfo: notification.request.content.userInfo)
        Task { @MainActor in
            handleRemoteNotification(payload)
        }
        completionHandler([.banner, .list, .sound, .badge])
    }

    nonisolated func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        didReceive response: UNNotificationResponse,
        withCompletionHandler completionHandler: @escaping () -> Void
    ) {
        let payload = PushPayload(userInfo: response.notification.request.content.userInfo)
        Task { @MainActor in
            handleRemoteNotification(payload)
            completionHandler()
        }
    }

    private func route(from payload: PushPayload) {
        guard let router else { return }

        switch payload.route {
        case .payment:
            navigateHomeRoute(.paymentCollection)
        case .order:
            router.selectOrders(entry: .storeOrders)
        case .verificationOrder:
            router.openWriteOffList()
        case .task:
            navigateHomeRoute(.taskManagement)
        case .queue:
            navigateHomeRoute(.queueManagement)
        case .messageCenter:
            navigateHomeRoute(.messageCenter)
        }
    }

    private func navigateHomeRoute(_ route: HomeRoute) {
        guard let router else { return }
        router.select(.home)
        router.router(for: .home).navigate(to: .home(route))
    }
}
