//
//  ScenicSpotContextTests.swift
//  suixinkanTests
//
//  Created by Codex on 2026/6/22.
//

import XCTest
@testable import suixinkan

@MainActor
/// 景点上下文测试，覆盖按景区懒加载和失败隔离。
final class ScenicSpotContextTests: XCTestCase {
    /// 测试景点列表会按当前景区 ID 请求并写入上下文。
    func testReloadRequestsSpotsForScenicId() async {
        let context = ScenicSpotContext()
        let api = MockScenicSpotAPI()
        api.spotResponse = ListPayload(total: 1, list: [ScenicSpotItem(id: 9, name: "观景台")])

        await context.reload(scenicId: 88, api: api)

        XCTAssertEqual(api.requestedScenicIds, [88])
        XCTAssertEqual(context.scenicId, 88)
        XCTAssertEqual(context.spots.map(\.id), [9])
        XCTAssertEqual(context.loadState, .loaded)
    }

    /// 测试景点接口失败时只标记景点模块失败。
    func testReloadFailureOnlyAffectsScenicSpotContext() async {
        let context = ScenicSpotContext()
        let api = MockScenicSpotAPI()
        api.error = APIError.networkFailed("景点接口失败")

        await context.reload(scenicId: 88, api: api)

        XCTAssertEqual(api.requestedScenicIds, [88])
        XCTAssertTrue(context.spots.isEmpty)
        if case .failed = context.loadState {
            XCTAssertTrue(true)
        } else {
            XCTFail("景点接口失败时应进入 failed 状态")
        }
    }
}

@MainActor
/// 景点服务测试替身，记录请求过的景区 ID。
private final class MockScenicSpotAPI: AccountContextServing {
    var requestedScenicIds: [Int] = []
    var spotResponse = ListPayload(total: 0, list: [ScenicSpotItem]())
    var error: Error?

    /// 获取空角色权限，当前测试不使用。
    func rolePermissions() async throws -> [RolePermissionResponse] {
        []
    }

    /// 获取空景区列表，当前测试不使用。
    func scenicListAll() async throws -> ScenicListAllResponse {
        ScenicListAllResponse(total: 0, list: [])
    }

    /// 获取空门店列表，当前测试不使用。
    func storeAll() async throws -> ListPayload<StoreItem> {
        ListPayload(total: 0, list: [])
    }

    /// 获取测试景点列表，并记录景区 ID。
    func scenicSpotListAll(scenicId: Int) async throws -> ListPayload<ScenicSpotItem> {
        requestedScenicIds.append(scenicId)
        if let error {
            throw error
        }
        return spotResponse
    }
}
