//
//  PermissionContext.swift
//  suixinkan
//
//  Created by Codex on 2026/6/22.
//

import Foundation
import Combine

@MainActor
/// 权限上下文状态中心，保存角色权限、当前角色和扁平化权限 URI。
final class PermissionContext: ObservableObject {
    @Published private(set) var rolePermissions: [RolePermissionResponse] = []
    @Published private(set) var permissionURIs: Set<String> = []
    @Published var currentRole: RoleInfo?

    /// 当前 App 业务角色，优先 role_code，兼容 legacy id 与角色名。
    var currentAppRole: AppRoleCode? {
        if let code = AppRoleCode.fromCode(currentRole?.roleCode) { return code }
        if let roleId = currentRole?.id, let code = AppRoleCode.fromLegacyRoleId(roleId) { return code }
        return AppRoleCode.fromRoleName(currentRole?.name)
    }

    /// 替换角色权限列表，并按 role_code 优先恢复当前角色。
    func replaceRolePermissions(
        _ rolePermissions: [RolePermissionResponse],
        currentRoleCode: String? = nil,
        cachedLegacyRoleId: Int? = nil,
        roleName: String? = nil
    ) {
        self.rolePermissions = rolePermissions
        let resolvedCode = RolePermissionMatching.resolveRoleCode(
            roleCode: currentRoleCode,
            roleId: cachedLegacyRoleId,
            roleName: roleName,
            permissions: rolePermissions
        )?.rawValue ?? currentRoleCode

        if let matched = RolePermissionMatching.match(
            in: rolePermissions,
            roleCode: resolvedCode,
            roleId: cachedLegacyRoleId,
            roleName: roleName ?? currentRole?.name
        ) {
            currentRole = matched.role
        } else if let currentRole,
                  let matched = rolePermissions.first(where: { $0.role.id == currentRole.id }) {
            self.currentRole = matched.role
        } else {
            currentRole = rolePermissions.first?.role
        }
        permissionURIs = Set(Self.flattenPermissions(currentRole?.permission ?? []))
    }

    /// 切换当前角色，并同步账号上下文中的景区和门店选择。
    func selectRole(code: AppRoleCode, accountContext: AccountContext) {
        guard let rolePermission = rolePermissions.first(where: {
            AppRoleCode.fromCode($0.role.roleCode) == code
        }) else { return }
        applyRoleSelection(rolePermission, accountContext: accountContext)
    }

    /// 切换当前角色（legacy id），供权限申请等仍使用 API role id 的场景。
    func selectRole(id roleId: Int, accountContext: AccountContext) {
        guard let rolePermission = rolePermissions.first(where: { $0.role.id == roleId }) else { return }
        applyRoleSelection(rolePermission, accountContext: accountContext)
    }

    /// 判断当前角色是否拥有指定 URI 权限。
    func canAccess(_ uri: String) -> Bool {
        permissionURIs.contains(uri.trimmingCharacters(in: .whitespacesAndNewlines))
    }

    /// 返回指定角色的顶层权限 URI 列表，顺序与 API 返回一致。
    func topLevelPermissionURIs(for roleCode: String?) -> [String] {
        topLevelPermissions(for: roleCode).map(\.uri)
    }

    /// 返回指定角色的顶层权限节点，顺序与 API 返回一致。
    func topLevelPermissions(for roleCode: String?) -> [PermissionItem] {
        guard let roleCode,
              let rolePermission = matchedRolePermission(roleCode: roleCode) else {
            return []
        }
        return rolePermission.role.permission.filter { item in
            !item.uri.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        }
    }

    /// 返回当前角色关联的景区作用域。
    func currentRoleScenicScopes() -> [BusinessScope] {
        guard let currentRole else { return [] }
        guard let rolePermission = matchedRolePermission(roleCode: currentRole.roleCode)
            ?? rolePermissions.first(where: { $0.role.id == currentRole.id }) else {
            return []
        }
        return Self.uniqueScenicScopes(from: rolePermission.scenic)
    }

    /// 清空权限上下文，通常在退出登录时调用。
    func reset() {
        rolePermissions = []
        permissionURIs = []
        currentRole = nil
    }

    /// 应用角色切换并同步景区作用域。
    private func applyRoleSelection(_ rolePermission: RolePermissionResponse, accountContext: AccountContext) {
        currentRole = rolePermission.role
        permissionURIs = Set(Self.flattenPermissions(rolePermission.role.permission))

        let scenicScopes = Self.uniqueScenicScopes(from: rolePermission.scenic)
        accountContext.replaceScopes(
            scenic: scenicScopes,
            stores: accountContext.storeScopes,
            currentScenicId: accountContext.currentScenic?.id,
            currentStoreId: accountContext.currentStore?.id
        )
    }

    /// 按 role_code 在权限列表中查找角色权限项。
    private func matchedRolePermission(roleCode: String) -> RolePermissionResponse? {
        RolePermissionMatching.match(
            in: rolePermissions,
            roleCode: roleCode,
            roleId: nil,
            roleName: nil
        )
    }

    /// 递归提取权限树里的非空 URI。
    private static func flattenPermissions(_ permissions: [PermissionItem]) -> [String] {
        permissions.flatMap { item -> [String] in
            let current = item.uri.trimmingCharacters(in: .whitespacesAndNewlines)
            let children = flattenPermissions(item.children)
            return current.isEmpty ? children : [current] + children
        }
    }

    /// 将角色关联景区去重并转换为业务作用域。
    private static func uniqueScenicScopes(from scenics: [ScenicInfo]) -> [BusinessScope] {
        var seen = Set<Int>()
        return scenics.compactMap { scenic in
            guard seen.insert(scenic.id).inserted else { return nil }
            return BusinessScope(
                id: scenic.id,
                name: scenic.name,
                kind: .scenic,
                status: scenic.status,
                address: scenic.location?.address,
                latitude: scenic.location?.lat,
                longitude: scenic.location?.lng,
                coverURLString: scenic.coverImg
            )
        }
    }
}
