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

import Foundation
import Observation

@MainActor
@Observable
/// 登录会话协调器，统一处理登录完成、退出登录和缓存同步。
final class AuthSessionCoordinator {
    @ObservationIgnored private let tokenStore: SessionTokenStore
    @ObservationIgnored private let snapshotStore: AccountSnapshotStore
    @ObservationIgnored private let preferencesStore: AppPreferencesStore

    /// 初始化登录会话协调器，并注入 token、账号快照和偏好存储。
    init(
        tokenStore: SessionTokenStore,
        snapshotStore: AccountSnapshotStore,
        preferencesStore: AppPreferencesStore
    ) {
        self.tokenStore = tokenStore
        self.snapshotStore = snapshotStore
        self.preferencesStore = preferencesStore
    }

    /// 创建使用默认存储服务的登录会话协调器。
    convenience init() {
        self.init(
            tokenStore: SessionTokenStore(),
            snapshotStore: AccountSnapshotStore(),
            preferencesStore: AppPreferencesStore()
        )
    }

    /// 读取登录页需要的本地偏好。
    func loginPreferences() -> LoginPreferences {
        LoginPreferences(
            lastUsername: preferencesStore.loadLastLoginUsername(),
            privacyAgreementAccepted: preferencesStore.loadPrivacyAgreementAccepted()
        )
    }

    /// 完成正式登录，写入内存状态、Keychain token 和账号快照。
    func completeLogin(
        with response: V9AuthResponse,
        username: String,
        privacyAgreementAccepted: Bool,
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        profileAPI: UserProfileServing,
        accountContextAPI: AccountContextServing
    ) async throws {
        let token = response.token.trimmingCharacters(in: .whitespacesAndNewlines)
        try tokenStore.save(token)
        preferencesStore.saveLastLoginUsername(username)
        preferencesStore.savePrivacyAgreementAccepted(privacyAgreementAccepted)

        let profile = response.primaryProfile
        let scenicScopes = response.scenicScopes
        let storeScopes = response.storeScopes
        let identity = response.currentAccountIdentity
        accountContext.applyLogin(profile: profile)
        accountContext.replaceScopes(scenic: scenicScopes, stores: storeScopes)
        appSession.beginRestoring(token: token)

        do {
            try await AccountContextLoader().refresh(
                accountContext: accountContext,
                permissionContext: permissionContext,
                profileAPI: profileAPI,
                accountContextAPI: accountContextAPI,
                cachedCurrentScenicId: accountContext.currentScenic?.id,
                cachedCurrentStoreId: accountContext.currentStore?.id
            )
        } catch {
            if APIError.isAuthenticationExpired(error) {
                try? tokenStore.clear()
                snapshotStore.clear()
                accountContext.reset()
                permissionContext.reset()
                appSession.logout()
                throw error
            }
            appSession.markLoggedIn(token: token)
            saveSnapshot(
                profile: accountContext.profile ?? profile,
                accountType: identity?.accountType,
                businessUserId: identity?.businessUserId,
                permissionContext: permissionContext,
                accountContext: accountContext
            )
            throw error
        }

        saveSnapshot(
            profile: accountContext.profile ?? profile,
            accountType: identity?.accountType,
            businessUserId: identity?.businessUserId,
            permissionContext: permissionContext,
            accountContext: accountContext
        )
        appSession.markLoggedIn(token: token)
    }

    /// 使用最新用户资料刷新账号快照中的展示信息。
    func refreshCachedProfile(from userInfo: UserInfoResponse, accountContext: AccountContext) {
        let profile = makeProfile(from: userInfo, fallback: accountContext.profile)
        accountContext.replaceProfile(profile)
        saveSnapshot(
            profile: profile,
            accountType: snapshotStore.load()?.accountType,
            businessUserId: snapshotStore.load()?.businessUserId,
            currentRoleId: snapshotStore.load()?.currentRoleId,
            accountContext: accountContext
        )
    }

    /// 退出登录并清空敏感缓存，保留手机号和协议状态等偏好。
    func logout(
        appSession: AppSession,
        accountContext: AccountContext,
        permissionContext: PermissionContext,
        scenicSpotContext: ScenicSpotContext,
        appRouter: AppRouter,
        toastCenter: ToastCenter
    ) {
        try? tokenStore.clear()
        snapshotStore.clear()
        accountContext.reset()
        permissionContext.reset()
        scenicSpotContext.reset()
        appRouter.reset()
        toastCenter.dismiss()
        appSession.logout()
    }

    /// 保存当前账号上下文的快照。
    private func saveSnapshot(
        profile: AccountProfile?,
        accountType: String?,
        businessUserId: Int?,
        permissionContext: PermissionContext? = nil,
        currentRoleId: Int? = nil,
        accountContext: AccountContext
    ) {
        snapshotStore.save(
            AccountSnapshot(
                profile: profile,
                accountType: accountType,
                businessUserId: businessUserId,
                currentRoleId: permissionContext?.currentRole?.id ?? currentRoleId,
                scenicScopes: accountContext.scenicScopes,
                storeScopes: accountContext.storeScopes,
                currentScenicId: accountContext.currentScenic?.id,
                currentStoreId: accountContext.currentStore?.id
            )
        )
    }

    /// 将用户资料接口响应转换为全局账号资料。
    private func makeProfile(from userInfo: UserInfoResponse, fallback: AccountProfile?) -> AccountProfile {
        AccountProfile(
            userId: fallback?.userId ?? "",
            displayName: nonEmpty(userInfo.nickname) ?? nonEmpty(userInfo.realName) ?? fallback?.displayName ?? "未设置昵称",
            phone: nonEmpty(userInfo.phone) ?? fallback?.phone,
            avatarURL: nonEmpty(userInfo.avatar) ?? fallback?.avatarURL
        )
    }

    /// 去除空白字符后返回非空字符串。
    private func nonEmpty(_ value: String?) -> String? {
        let text = value?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        return text.isEmpty ? nil : text
    }
}

/// 登录页偏好实体，表示可安全恢复到表单的非敏感信息。
struct LoginPreferences: Equatable {
    let lastUsername: String?
    let privacyAgreementAccepted: Bool
}

private extension V9AuthResponse {
    /// 当前账号身份实体，表示登录后实际选中的业务账号。
    struct CurrentAccountIdentity {
        let accountType: String
        let businessUserId: Int
    }

    /// 提取当前账号身份，优先使用后端标记的 isCurrent 账号。
    var currentAccountIdentity: CurrentAccountIdentity? {
        if let storeUser = storeUsers.first(where: \.isCurrent) ?? storeUsers.first {
            return CurrentAccountIdentity(
                accountType: storeUser.accountType,
                businessUserId: storeUser.businessUserId
            )
        }
        if let scenicUser = scenicUsers.first(where: \.isCurrent) ?? scenicUsers.first {
            return CurrentAccountIdentity(
                accountType: scenicUser.accountType,
                businessUserId: scenicUser.businessUserId
            )
        }
        return nil
    }
}
