//
//  SessionBootstrapper.swift
//  suixinkan
//
//  Created by Codex on 2026/6/20.
//

import Foundation
import Combine

@MainActor
/// 登录态启动恢复器，负责冷启动时从缓存恢复并校验 token。
final class SessionBootstrapper {
    private let tokenStore: SessionTokenStore
    private let snapshotStore: AccountSnapshotStore
    private var didAttemptRestore = false

    /// 初始化启动恢复器，并注入 token 与账号快照存储。
    init(
        tokenStore: SessionTokenStore,
        snapshotStore: AccountSnapshotStore
    ) {
        self.tokenStore = tokenStore
        self.snapshotStore = snapshotStore
    }

    /// 创建使用默认存储服务的启动恢复器。
    convenience init() {
        self.init(
            tokenStore: SessionTokenStore(),
            snapshotStore: AccountSnapshotStore()
        )
    }

    /// 从本地缓存恢复登录态；阻塞等待 rolePermissions，其余数据后台刷新。
    func restore(
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        profileAPI: UserProfileServing,
        accountContextAPI: AccountContextServing,
        toastCenter: ToastCenter
    ) async {
        guard !didAttemptRestore, !appSession.isLoggedIn else { return }
        didAttemptRestore = true

        guard let token = tokenStore.load() else {
            appSession.logout()
            return
        }

        appSession.beginRestoring(token: token)
        let cachedSnapshot = restoreCachedSnapshot(to: accountContext)
        let loader = AccountContextLoader()

        do {
            try await loader.restorePermissions(
                permissionContext: permissionContext,
                accountContext: accountContext,
                accountContextAPI: accountContextAPI,
                cachedCurrentRoleCode: cachedSnapshot?.currentRoleCode,
                cachedLegacyRoleId: cachedSnapshot?.currentRoleId,
                cachedCurrentScenicId: cachedSnapshot?.currentScenicId,
                cachedCurrentStoreId: cachedSnapshot?.currentStoreId
            )
            appSession.markLoggedIn(token: token)
            refreshSupplementalContextInBackground(
                loader: loader,
                appSession: appSession,
                accountContext: accountContext,
                permissionContext: permissionContext,
                profileAPI: profileAPI,
                accountContextAPI: accountContextAPI,
                toastCenter: toastCenter,
                cachedSnapshot: cachedSnapshot
            )
        } catch {
            handleBlockingRestoreFailure(
                error,
                token: token,
                appSession: appSession,
                accountContext: accountContext,
                permissionContext: permissionContext,
                toastCenter: toastCenter
            )
        }
    }

    /// 将缓存快照恢复到账号上下文。
    private func restoreCachedSnapshot(to accountContext: AccountContext) -> AccountSnapshot? {
        guard let snapshot = snapshotStore.load() else { return nil }
        accountContext.applyLogin(
            profile: snapshot.profile,
            accountType: snapshot.accountType,
            businessUserId: snapshot.businessUserId,
            displayTitle: snapshot.currentAccountDisplayTitle
        )
        accountContext.replaceScopes(
            scenic: snapshot.scenicScopes,
            stores: snapshot.storeScopes,
            currentScenicId: snapshot.currentScenicId,
            currentStoreId: snapshot.currentStoreId,
            explicitSelection: true
        )
        return snapshot
    }

    /// 后台补齐用户资料、景区和门店，不阻塞进入主界面。
    private func refreshSupplementalContextInBackground(
        loader: AccountContextLoader,
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        profileAPI: UserProfileServing,
        accountContextAPI: AccountContextServing,
        toastCenter: ToastCenter,
        cachedSnapshot: AccountSnapshot?
    ) {
        Task {
            do {
                try await loader.refreshSupplementalContext(
                    accountContext: accountContext,
                    permissionContext: permissionContext,
                    profileAPI: profileAPI,
                    accountContextAPI: accountContextAPI,
                    cachedCurrentScenicId: cachedSnapshot?.currentScenicId,
                    cachedCurrentStoreId: cachedSnapshot?.currentStoreId
                )
                saveLatestSnapshot(from: accountContext, permissionContext: permissionContext)
            } catch {
                handleSupplementalRefreshFailure(
                    error,
                    appSession: appSession,
                    accountContext: accountContext,
                    permissionContext: permissionContext,
                    toastCenter: toastCenter
                )
            }
        }
    }

    /// 处理阻塞阶段恢复失败：鉴权失效登出，网络异常则降级为本地登录态。
    private func handleBlockingRestoreFailure(
        _ error: Error,
        token: String,
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        toastCenter: ToastCenter
    ) {
        if APIError.isAuthenticationExpired(error) {
            clearPersistedSession(
                appSession: appSession,
                accountContext: accountContext,
                permissionContext: permissionContext
            )
            toastCenter.show("登录状态已失效，请重新登录")
            return
        }

        appSession.markLoggedIn(token: token)
        toastCenter.show("网络异常，已使用本地登录状态")
    }

    /// 处理后台补充刷新失败：鉴权失效登出，网络异常保留当前登录态。
    private func handleSupplementalRefreshFailure(
        _ error: Error,
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        toastCenter: ToastCenter
    ) {
        if APIError.isAuthenticationExpired(error) {
            clearPersistedSession(
                appSession: appSession,
                accountContext: accountContext,
                permissionContext: permissionContext
            )
            toastCenter.show("登录状态已失效，请重新登录")
            return
        }

        toastCenter.show("网络异常，已使用本地登录状态")
    }

    /// 清空本地 token、快照和内存上下文。
    private func clearPersistedSession(
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext
    ) {
        try? tokenStore.clear()
        snapshotStore.clear()
        accountContext.reset()
        permissionContext.reset()
        appSession.logout()
    }

    /// 保存服务端校验后的最新账号上下文。
    private func saveLatestSnapshot(from accountContext: AccountContext, permissionContext: PermissionContext) {
        let existing = snapshotStore.load()
        snapshotStore.save(
            AccountSnapshot(
                profile: accountContext.profile,
                accountType: accountContext.accountType ?? existing?.accountType,
                businessUserId: existing?.businessUserId,
                currentAccountDisplayTitle: accountContext.currentAccountDisplayTitle ?? existing?.currentAccountDisplayTitle,
                currentRoleCode: permissionContext.currentAppRole?.rawValue ?? existing?.currentRoleCode,
                scenicScopes: accountContext.scenicScopes,
                storeScopes: accountContext.storeScopes,
                currentScenicId: accountContext.currentScenic?.id,
                currentStoreId: accountContext.currentStore?.id
            )
        )
    }
}
