//
//  AccountContext.swift
//  suixinkan
//
//  Created by Codex on 2026/6/18.
//

import Observation

/// 当前账号的基础资料实体，用于跨页面展示昵称、手机号和头像。
struct AccountProfile: Codable, Equatable {
    var userId: String
    var displayName: String
    var phone: String?
    var avatarURL: String?
}

/// 当前业务作用域实体，表示景区或门店维度的上下文。
struct BusinessScope: Codable, Equatable, Identifiable {
    /// 业务作用域类型，用于区分景区和门店。
    enum Kind: Codable, Equatable {
        case scenic
        case store
    }

    var id: Int
    var name: String
    var kind: Kind
    var parentScenicId: Int?
    var status: Int?
    var address: String?
    var latitude: Double?
    var longitude: Double?
    var coverURLString: String?

    /// 创建业务作用域，门店可通过 parentScenicId 标记所属景区。
    init(
        id: Int,
        name: String,
        kind: Kind,
        parentScenicId: Int? = nil,
        status: Int? = nil,
        address: String? = nil,
        latitude: Double? = nil,
        longitude: Double? = nil,
        coverURLString: String? = nil
    ) {
        self.id = id
        self.name = name
        self.kind = kind
        self.parentScenicId = parentScenicId
        self.status = status
        self.address = address
        self.latitude = latitude
        self.longitude = longitude
        self.coverURLString = coverURLString
    }
}

@MainActor
@Observable
/// 账号上下文状态中心，保存当前账号资料和景区/门店作用域。
final class AccountContext {
    private(set) var profile: AccountProfile?
    private(set) var scenicScopes: [BusinessScope] = []
    private(set) var storeScopes: [BusinessScope] = []
    var currentScenic: BusinessScope?
    var currentStore: BusinessScope?

    /// 应用登录成功后写入账号资料。
    func applyLogin(profile: AccountProfile? = nil) {
        self.profile = profile
    }

    /// 替换当前账号资料，通常用于用户信息刷新后同步全局展示。
    func replaceProfile(_ profile: AccountProfile?) {
        self.profile = profile
    }

    /// 替换景区和门店作用域，并尽量保持当前选择不变。
    func replaceScopes(
        scenic: [BusinessScope],
        stores: [BusinessScope],
        currentScenicId: Int? = nil,
        currentStoreId: Int? = nil
    ) {
        scenicScopes = scenic
        storeScopes = stores
        currentScenic = currentScenicId.flatMap { id in
            scenic.first { $0.id == id }
        } ?? currentScenic.flatMap { current in
            scenic.first { $0.id == current.id }
        } ?? scenic.first
        currentStore = resolvedStore(
            in: stores,
            currentScenic: currentScenic,
            preferredStoreId: currentStoreId ?? currentStore?.id
        )
    }

    /// 切换当前景区，并按景区重新校准当前门店。
    func selectScenic(id scenicId: Int) {
        guard let scenic = scenicScopes.first(where: { $0.id == scenicId }) else { return }
        currentScenic = scenic
        currentStore = resolvedStore(
            in: storeScopes,
            currentScenic: scenic,
            preferredStoreId: currentStore?.id
        )
    }

    /// 切换当前门店，并在门店有关联景区时同步当前景区。
    func selectStore(id storeId: Int) {
        guard let store = storeScopes.first(where: { $0.id == storeId }) else { return }
        currentStore = store
        if let scenicId = store.parentScenicId,
           currentScenic?.id != scenicId,
           let scenic = scenicScopes.first(where: { $0.id == scenicId }) {
            currentScenic = scenic
        }
    }

    /// 清空账号上下文，通常在退出登录时调用。
    func reset() {
        profile = nil
        scenicScopes = []
        storeScopes = []
        currentScenic = nil
        currentStore = nil
    }

    /// 按当前景区和期望门店 ID 选择有效门店。
    private func resolvedStore(
        in stores: [BusinessScope],
        currentScenic: BusinessScope?,
        preferredStoreId: Int?
    ) -> BusinessScope? {
        let scenicId = currentScenic?.id
        let storesForScenic = stores.filter { store in
            guard let scenicId else { return true }
            return store.parentScenicId == nil || store.parentScenicId == scenicId
        }
        if let preferredStoreId,
           let store = storesForScenic.first(where: { $0.id == preferredStoreId }) {
            return store
        }
        return storesForScenic.first
    }
}
