//
//  AppStore.swift
//  suixinkan
//

import Foundation

/// 本地会话存储，与 Android `AppStoreDataSource` 对齐。
final class AppStore {

    static let shared = AppStore()

    private enum Key {
        static let token = "key_in_token"
        static let lastLoginUsername = "key_last_login_username"
        static let privacyAgreementAccepted = "key_privacy_agreement_accepted"
        static let userId = "key_in_user_id"
        static let userName = "key_in_user_name"
        static let realName = "key_in_real_name"
        static let avatar = "key_in_avatar"
        static let phone = "key_in_phone"
        static let accountType = "key_in_account_type"
        static let accountDisplayName = "key_in_account_display_name"
        static let roleCode = "key_in_role_code"
        static let roleName = "key_in_role_name"
        static let currentScenicId = "key_in_current_scenic_id"
        static let currentScenicName = "key_in_current_scenic_name"
        static let currentStoreId = "key_in_current_store_id"
        static let legacyRoleId = "key_in_role_id"
        static let rolePermissionList = "key_role_permission_list"
        static let permissionItems = "key_in_permission"
        static let roleScenicList = "key_current_role_scenic_list"
        static let onlineStatus = "key_online_status"
        static let lastLocationReportTime = "key_last_location_report_time"
        static let locationReminderMinutes = "key_location_reminder_minutes"
        static let isOpenReceiveVoice = "key_is_open_receive_voice"
        static let scenicQueuePunchSpotId = "_scenic_queue_punch_spot_id"
        static let scenicQueuePunchSpotName = "_scenic_queue_punch_spot_name"
        static let scenicQueueRemark = "_scenic_queue_remark"
        static let scenicQueueSettingsSnapshot = "_scenic_queue_settings_snapshot"
        static let scenicQueueOfflineTTS = "_scenic_queue_offline_tts_v1"
        static let scenicQueuePresetVoices = "_scenic_queue_preset_voices_v1"
    }

    private let defaults: UserDefaults

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults
    }

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

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

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

    var userId: String {
        get { defaults.string(forKey: Key.userId) ?? "" }
        set { defaults.set(newValue, forKey: Key.userId) }
    }

    var userName: String {
        get { defaults.string(forKey: Key.userName) ?? "" }
        set { defaults.set(newValue, forKey: Key.userName) }
    }

    var realName: String {
        get { defaults.string(forKey: Key.realName) ?? "" }
        set { defaults.set(newValue, forKey: Key.realName) }
    }

    var avatar: String {
        get { defaults.string(forKey: Key.avatar) ?? "" }
        set { defaults.set(newValue, forKey: Key.avatar) }
    }

    var phone: String {
        get { defaults.string(forKey: Key.phone) ?? "" }
        set { defaults.set(newValue, forKey: Key.phone) }
    }

    var accountType: String {
        get { defaults.string(forKey: Key.accountType) ?? "" }
        set { defaults.set(newValue, forKey: Key.accountType) }
    }

    var accountDisplayName: String {
        get { defaults.string(forKey: Key.accountDisplayName) ?? "" }
        set { defaults.set(newValue, forKey: Key.accountDisplayName) }
    }

    var roleCode: String {
        get { defaults.string(forKey: Key.roleCode) ?? "" }
        set { defaults.set(newValue, forKey: Key.roleCode) }
    }

    var roleName: String {
        get { defaults.string(forKey: Key.roleName) ?? "" }
        set { defaults.set(newValue, forKey: Key.roleName) }
    }

    var currentScenicId: Int {
        get {
            let value = defaults.string(forKey: Key.currentScenicId) ?? ""
            return Int(value) ?? 0
        }
        set {
            defaults.set(newValue > 0 ? String(newValue) : "", forKey: Key.currentScenicId)
        }
    }

    var currentScenicName: String {
        get { defaults.string(forKey: Key.currentScenicName) ?? "" }
        set { defaults.set(newValue, forKey: Key.currentScenicName) }
    }

    var currentStoreId: Int {
        get { defaults.integer(forKey: Key.currentStoreId) }
        set { defaults.set(newValue, forKey: Key.currentStoreId) }
    }

    /// 旧版 role_id，用于权限匹配兜底。
    var legacyRoleId: Int {
        get { defaults.integer(forKey: accountScopedKey(Key.legacyRoleId)) }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.legacyRoleId)) }
    }

    /// 是否在线（位置上报会话）。
    var onlineStatus: Bool {
        get { defaults.bool(forKey: accountScopedKey(Key.onlineStatus)) }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.onlineStatus)) }
    }

    /// 上次位置上报时间戳（毫秒）。
    var lastLocationReportTime: Int64 {
        get { Int64(defaults.integer(forKey: accountScopedKey(Key.lastLocationReportTime))) }
        set { defaults.set(Int(newValue), forKey: accountScopedKey(Key.lastLocationReportTime)) }
    }

    /// 位置超时提前提醒分钟数，0 表示不提醒。
    var locationReminderMinutes: Int {
        get { defaults.integer(forKey: accountScopedKey(Key.locationReminderMinutes)) }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.locationReminderMinutes)) }
    }

    /// 收款到账是否开启语音播报，对齐 Android `getIsOpenReceiveVoice`。
    var isOpenReceiveVoice: Bool {
        get { defaults.bool(forKey: accountScopedKey(Key.isOpenReceiveVoice)) }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.isOpenReceiveVoice)) }
    }

    /// 排队管理已保存打卡点 ID。
    var scenicQueuePunchSpotId: String {
        get { defaults.string(forKey: accountScopedKey(Key.scenicQueuePunchSpotId)) ?? "" }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.scenicQueuePunchSpotId)) }
    }

    /// 排队管理已保存打卡点名称。
    var scenicQueuePunchSpotName: String {
        get { defaults.string(forKey: accountScopedKey(Key.scenicQueuePunchSpotName)) ?? "" }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.scenicQueuePunchSpotName)) }
    }

    /// 排队管理自定义播报文案。
    var scenicQueueRemark: String {
        get { defaults.string(forKey: accountScopedKey(Key.scenicQueueRemark)) ?? "" }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.scenicQueueRemark)) }
    }

    /// 排队语音是否优先使用离线 TTS。
    var scenicQueueUseOfflineTTS: Bool {
        get { defaults.bool(forKey: accountScopedKey(Key.scenicQueueOfflineTTS)) }
        set { defaults.set(newValue, forKey: accountScopedKey(Key.scenicQueueOfflineTTS)) }
    }

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

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

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

    /// Token 非空视为已登录。
    var isLoggedIn: Bool {
        !token.isEmpty
    }

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

    /// 从账号切换实体写入会话快照。
    func applyAccount(_ account: AccountSwitchAccount) {
        userId = String(account.businessUserId)
        accountType = 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 logout() {
        clearPermissionSnapshot()
        token = ""
        userId = ""
        userName = ""
        realName = ""
        avatar = ""
        phone = ""
        accountType = ""
        accountDisplayName = ""
        roleCode = ""
        roleName = ""
        currentScenicId = 0
        currentScenicName = ""
        currentStoreId = 0
    }

    /// 保存完整 role-permission 列表。
    func saveRolePermissionList(_ list: [RolePermissionResponse]) {
        guard let data = try? JSONEncoder().encode(list) else { return }
        defaults.set(data, forKey: accountScopedKey(Key.rolePermissionList))
    }

    /// 读取完整 role-permission 列表。
    func rolePermissionList() -> [RolePermissionResponse] {
        guard let data = defaults.data(forKey: accountScopedKey(Key.rolePermissionList)),
              let list = try? JSONDecoder().decode([RolePermissionResponse].self, from: data) else {
            return []
        }
        return list
    }

    /// 保存当前角色扁平权限。
    func savePermissionItems(_ items: [HomePermissionItem]) {
        guard let data = try? JSONEncoder().encode(items) else { return }
        defaults.set(data, forKey: accountScopedKey(Key.permissionItems))
    }

    /// 读取当前角色扁平权限。
    func permissionItems() -> [HomePermissionItem] {
        guard let data = defaults.data(forKey: accountScopedKey(Key.permissionItems)),
              let items = try? JSONDecoder().decode([HomePermissionItem].self, from: data) else {
            return []
        }
        return items
    }

    /// 保存当前角色可选景区列表。
    func saveRoleScenicList(_ scenicList: [ScenicInfo]) {
        guard let data = try? JSONEncoder().encode(scenicList) else { return }
        defaults.set(data, forKey: accountScopedKey(Key.roleScenicList))
    }

    /// 读取当前角色可选景区列表。
    func roleScenicList() -> [ScenicInfo] {
        guard let data = defaults.data(forKey: accountScopedKey(Key.roleScenicList)),
              let list = try? JSONDecoder().decode([ScenicInfo].self, from: data) else {
            return []
        }
        return list
    }

    /// 在 role-permission 列表中匹配当前账号角色。
    func matchRolePermissionItem(in list: [RolePermissionResponse]) -> RolePermissionResponse? {
        RolePermissionMatcher.match(
            in: list,
            roleCode: roleCode,
            roleName: roleName,
            legacyRoleId: legacyRoleId
        )
    }

    /// 清除上次位置上报时间。
    func clearLastLocationReportTime() {
        defaults.removeObject(forKey: accountScopedKey(Key.lastLocationReportTime))
    }

    /// 是否已经保存排队打卡点。
    func hasScenicQueuePunchSpotSaved() -> Bool {
        let id = scenicQueuePunchSpotId.trimmingCharacters(in: .whitespacesAndNewlines)
        return Int64(id).map { $0 > 0 } ?? false
    }

    /// 保存排队设置快照。
    func saveScenicQueueSettingsSnapshot(_ snapshot: ScenicQueueSettingsSnapshot) {
        guard let data = try? JSONEncoder().encode(snapshot) else { return }
        defaults.set(data, forKey: accountScopedKey(Key.scenicQueueSettingsSnapshot))
    }

    /// 读取排队设置快照。
    func scenicQueueSettingsSnapshot() -> ScenicQueueSettingsSnapshot? {
        guard let data = defaults.data(forKey: accountScopedKey(Key.scenicQueueSettingsSnapshot)) else { return nil }
        return try? JSONDecoder().decode(ScenicQueueSettingsSnapshot.self, from: data)
    }

    /// 保存排队预设播报文案，最多 5 条。
    func saveScenicQueuePresetVoices(_ voices: [String]) {
        let normalized = voices
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }
            .prefix(5)
        defaults.set(Array(normalized), forKey: accountScopedKey(Key.scenicQueuePresetVoices))
    }

    /// 读取排队预设播报文案。
    func scenicQueuePresetVoices() -> [String] {
        defaults.stringArray(forKey: accountScopedKey(Key.scenicQueuePresetVoices)) ?? []
    }

    /// 清除排队管理本地缓存。
    func clearScenicQueueSnapshot() {
        [
            Key.scenicQueuePunchSpotId,
            Key.scenicQueuePunchSpotName,
            Key.scenicQueueRemark,
            Key.scenicQueueSettingsSnapshot,
            Key.scenicQueueOfflineTTS,
            Key.scenicQueuePresetVoices,
        ].forEach { defaults.removeObject(forKey: accountScopedKey($0)) }
    }

    /// 清除权限与位置会话快照。
    func clearPermissionSnapshot() {
        let prefix = accountScopedKey("")
        let keys = [
            Key.rolePermissionList,
            Key.permissionItems,
            Key.roleScenicList,
            Key.onlineStatus,
            Key.lastLocationReportTime,
            Key.locationReminderMinutes,
            Key.isOpenReceiveVoice,
            Key.scenicQueuePunchSpotId,
            Key.scenicQueuePunchSpotName,
            Key.scenicQueueRemark,
            Key.scenicQueueSettingsSnapshot,
            Key.scenicQueueOfflineTTS,
            Key.scenicQueuePresetVoices,
        ]
        keys.forEach { defaults.removeObject(forKey: prefix + $0) }
    }

    private func accountScopedKey(_ key: String) -> String {
        "\(accountCachePrefix)_\(key)"
    }
}
