//
//  AppSessionStore.swift
//  suixinkan
//

import Foundation

/// 应用账号类型，保留后端返回的未知类型以兼容后续扩展。
enum AppAccountType: Equatable, Sendable {
    case scenicUser
    case storeUser
    case unknown(String)

    /// 从持久化或后端原始值创建账号类型。
    init(rawValue: String) {
        switch rawValue {
        case "scenic_user": self = .scenicUser
        case "store_user": self = .storeUser
        default: self = .unknown(rawValue)
        }
    }

    /// 用于接口与持久化的原始字符串。
    var rawValue: String {
        switch self {
        case .scenicUser: "scenic_user"
        case .storeUser: "store_user"
        case let .unknown(value): value
        }
    }
}

/// 管理登录凭证、用户资料、账号角色及当前业务上下文。
final class AppSessionStore {

    private enum Key: String {
        case token = "key_in_token"
        case lastLoginUsername = "key_last_login_username"
        case privacyAgreementAccepted = "key_privacy_agreement_accepted"
        case userId = "key_in_user_id"
        case userName = "key_in_user_name"
        case realName = "key_in_real_name"
        case avatar = "key_in_avatar"
        case phone = "key_in_phone"
        case accountType = "key_in_account_type"
        case accountDisplayName = "key_in_account_display_name"
    }

    private enum AccountKey: String, CaseIterable {
        case roleCode = "key_in_role_code"
        case roleName = "key_in_role_name"
        case currentScenicId = "key_in_current_scenic_id"
        case currentScenicName = "key_in_current_scenic_name"
    }

    private static let currentStoreIdSuffix = "scenic_store_id"

    private let defaults: UserDefaults

    /// 使用指定 UserDefaults 创建会话存储。
    init(defaults: UserDefaults) {
        self.defaults = defaults
    }

    /// 登录 Token。
    var token: String {
        get { string(for: .token) }
        set { defaults.set(newValue, forKey: Key.token.rawValue) }
    }

    /// 上次登录手机号，用于登录页恢复。
    var lastLoginUsername: String? {
        get { defaults.string(forKey: Key.lastLoginUsername.rawValue) }
        set {
            if let newValue {
                defaults.set(newValue, forKey: Key.lastLoginUsername.rawValue)
            } else {
                defaults.removeObject(forKey: Key.lastLoginUsername.rawValue)
            }
        }
    }

    /// 是否已同意隐私协议。
    var privacyAgreementAccepted: Bool {
        get { defaults.bool(forKey: Key.privacyAgreementAccepted.rawValue) }
        set { defaults.set(newValue, forKey: Key.privacyAgreementAccepted.rawValue) }
    }

    /// 当前业务用户 ID。
    var userId: String {
        get { string(for: .userId) }
        set { defaults.set(newValue, forKey: Key.userId.rawValue) }
    }

    /// 当前用户展示名称。
    var userName: String {
        get { string(for: .userName) }
        set { defaults.set(newValue, forKey: Key.userName.rawValue) }
    }

    /// 当前用户真实姓名。
    var realName: String {
        get { string(for: .realName) }
        set { defaults.set(newValue, forKey: Key.realName.rawValue) }
    }

    /// 当前用户头像地址。
    var avatar: String {
        get { string(for: .avatar) }
        set { defaults.set(newValue, forKey: Key.avatar.rawValue) }
    }

    /// 当前用户手机号。
    var phone: String {
        get { string(for: .phone) }
        set { defaults.set(newValue, forKey: Key.phone.rawValue) }
    }

    /// 当前账号业务类型。
    var accountType: AppAccountType {
        get { AppAccountType(rawValue: string(for: .accountType)) }
        set { defaults.set(newValue.rawValue, forKey: Key.accountType.rawValue) }
    }

    /// 当前账号展示名称。
    var accountDisplayName: String {
        get { string(for: .accountDisplayName) }
        set { defaults.set(newValue, forKey: Key.accountDisplayName.rawValue) }
    }

    /// 后端返回的原始角色编码。
    var roleCode: String {
        get { accountString(for: .roleCode) }
        set { setAccountString(newValue, for: .roleCode) }
    }

    /// 当前角色名称。
    var roleName: String {
        get { accountString(for: .roleName) }
        set { setAccountString(newValue, for: .roleName) }
    }

    /// 当前景区 ID，0 表示未选择。
    var currentScenicId: Int {
        get { Int(accountString(for: .currentScenicId)) ?? 0 }
        set { setAccountString(newValue > 0 ? String(newValue) : "", for: .currentScenicId) }
    }

    /// 当前景区名称。
    var currentScenicName: String {
        get { accountString(for: .currentScenicName) }
        set { setAccountString(newValue, for: .currentScenicName) }
    }

    /// 当前店铺 ID，0 表示未选择。
    var currentStoreId: Int {
        get {
            guard let key = scenicScopedKey(Self.currentStoreIdSuffix) else { return 0 }
            return defaults.integer(forKey: key)
        }
        set {
            guard let key = scenicScopedKey(Self.currentStoreIdSuffix) else { return }
            defaults.set(newValue, forKey: key)
        }
    }

    /// 当前账号缓存前缀，对齐 Android `getAccountCachePrefix`。
    var accountCachePrefix: String {
        let uid = userId.trimmingCharacters(in: .whitespacesAndNewlines)
        let type = accountType.rawValue.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !uid.isEmpty, !type.isEmpty else { return "" }
        return "\(type)_\(uid)"
    }

    /// 为当前完整账号生成账号作用域 Key；账号信息不完整时返回 nil。
    func accountScopedKey(_ suffix: String) -> String? {
        let scope = accountCachePrefix
        let normalizedSuffix = suffix.trimmingCharacters(in: CharacterSet(charactersIn: "_"))
        guard !scope.isEmpty, !normalizedSuffix.isEmpty else { return nil }
        return "\(scope)_\(normalizedSuffix)"
    }

    /// 为当前账号与景区生成作用域 Key；缺少账号或景区时返回 nil。
    func scenicScopedKey(_ suffix: String, scenicId: Int? = nil) -> String? {
        let resolvedScenicId = scenicId ?? currentScenicId
        let normalizedSuffix = suffix.trimmingCharacters(in: CharacterSet(charactersIn: "_"))
        guard !accountCachePrefix.isEmpty, resolvedScenicId > 0, !normalizedSuffix.isEmpty else { return nil }
        return "\(accountCachePrefix)_scenic_\(resolvedScenicId)_\(normalizedSuffix)"
    }

    /// 为当前账号、景区与点位生成作用域 Key；任一业务标识缺失时返回 nil。
    func scenicSpotScopedKey(_ suffix: String, spotId: String, scenicId: Int? = nil) -> String? {
        let resolvedScenicId = scenicId ?? currentScenicId
        let normalizedSpotId = spotId.trimmingCharacters(in: .whitespacesAndNewlines)
        let normalizedSuffix = suffix.trimmingCharacters(in: CharacterSet(charactersIn: "_"))
        guard !accountCachePrefix.isEmpty,
              resolvedScenicId > 0,
              !normalizedSpotId.isEmpty,
              !normalizedSuffix.isEmpty else { return nil }
        return "\(accountCachePrefix)_scenic_\(resolvedScenicId)_spot_\(normalizedSpotId)_\(normalizedSuffix)"
    }

    /// 当前解析后的业务角色。
    var currentAppRole: AppRoleCode? {
        AppRoleCode.fromCode(roleCode) ?? AppRoleCode.fromRoleName(roleName)
    }

    /// 当前是否为摄影师角色。
    var isPhotographerRole: Bool {
        if let role = currentAppRole {
            return role.isPhotographer
        }
        return roleName.trimmingCharacters(in: .whitespacesAndNewlines) == "摄影师"
    }

    /// Token 非空时表示已登录。
    var isLoggedIn: Bool {
        !token.isEmpty
    }

    /// 保存登录 Token。
    func saveToken(_ token: String) {
        self.token = token
    }

    /// 从账号切换实体写入会话快照。
    func applyAccount(_ account: AccountSwitchAccount) {
        userId = String(account.businessUserId)
        accountType = AppAccountType(rawValue: account.accountType)
        accountDisplayName = account.title
        userName = account.subtitle
        phone = account.phone
        if !account.avatar.isEmpty {
            avatar = account.avatar
        }
        currentScenicName = account.scenicName
        currentScenicId = account.scenicId ?? 0
        currentStoreId = account.storeId ?? 0
    }

    /// 从用户资料接口回写展示字段。
    func applyUserInfo(_ info: UserInfoResponse) {
        if !info.nickname.isEmpty { userName = info.nickname }
        if !info.realName.isEmpty { realName = info.realName }
        if !info.avatar.isEmpty { avatar = info.avatar }
        if !info.phone.isEmpty { phone = info.phone }
        if !info.roleName.isEmpty, roleName.isEmpty { roleName = info.roleName }
    }

    /// 清除登录态及账号快照，保留隐私授权和上次登录用户名。
    func clearAuthenticatedSession(accountScope: String) {
        if !accountScope.isEmpty {
            AccountKey.allCases.forEach {
                defaults.removeObject(forKey: "\(accountScope)_\($0.rawValue)")
            }
            let storePrefix = "\(accountScope)_scenic_"
            let storeSuffix = "_\(Self.currentStoreIdSuffix)"
            defaults.dictionaryRepresentation().keys
                .filter { $0.hasPrefix(storePrefix) && $0.hasSuffix(storeSuffix) }
                .forEach(defaults.removeObject(forKey:))
        }

        [
            Key.token,
            .userId,
            .userName,
            .realName,
            .avatar,
            .phone,
            .accountType,
            .accountDisplayName,
        ].forEach { defaults.removeObject(forKey: $0.rawValue) }
    }

    private func string(for key: Key) -> String {
        defaults.string(forKey: key.rawValue) ?? ""
    }

    private func accountString(for key: AccountKey) -> String {
        guard let scopedKey = accountScopedKey(key.rawValue) else { return "" }
        return defaults.string(forKey: scopedKey) ?? ""
    }

    private func setAccountString(_ value: String, for key: AccountKey) {
        guard let scopedKey = accountScopedKey(key.rawValue) else { return }
        defaults.set(value, forKey: scopedKey)
    }
}
