//
//  LocationReportServiceTests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

@MainActor
/// 位置上报共享服务测试。
final class LocationReportServiceTests: XCTestCase {

    private var appStore: AppStore!
    private var defaults: UserDefaults!

    override func setUp() {
        defaults = UserDefaults(suiteName: "LocationReportServiceTests")!
        defaults.removePersistentDomain(forName: "LocationReportServiceTests")
        appStore = AppStore(defaults: defaults)
        appStore.session.configureTestAccount(userId: "staff-1", scenicId: 100)
    }

    override func tearDown() {
        appStore.logout()
        super.tearDown()
    }

    func testReportLocationDecodesNumericStaffId() async throws {
        let reportJSON = """
        {"code":100000,"msg":"success","data":{"staff_id":732,"expired":1783403917,"status":1,"store_user_id":732}}
        """.data(using: .utf8)!
        let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [reportJSON])))
        let stateStore = HomeLocationStateStore(store: appStore)
        let service = LocationReportService(appStore: appStore, locationStateStore: stateStore)

        let result = try await service.reportWithCoordinates(
            api: api,
            latitude: 32.429921061197916,
            longitude: 119.44032958984376,
            address: "测试地址",
            type: 1
        )

        XCTAssertTrue(result.shouldShowSuccessDialog)
        XCTAssertTrue(stateStore.isOnline)
    }

    func testReportWithCoordinatesType2UsesProvidedLocation() async throws {
        let reportJSON = """
        {"code":100000,"msg":"success","data":{"staff_id":"staff-1","expired":0,"status":1}}
        """.data(using: .utf8)!
        let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [reportJSON])))
        let stateStore = HomeLocationStateStore(store: appStore)
        let service = LocationReportService(appStore: appStore, locationStateStore: stateStore)

        let result = try await service.reportWithCoordinates(
            api: api,
            latitude: 30.1,
            longitude: 120.2,
            address: "标记地址",
            type: 2
        )

        XCTAssertTrue(result.shouldShowSuccessDialog)
        XCTAssertEqual(result.locationInfoText, "标记地址")
        XCTAssertTrue(stateStore.isOnline)
    }

    func testManualReportUsesLowerLocationAccuracy() async throws {
        let reportJSON = """
        {"code":100000,"msg":"success","data":{"staff_id":"staff-1","expired":0,"status":1}}
        """.data(using: .utf8)!
        let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [reportJSON])))
        let stateStore = HomeLocationStateStore(store: appStore)
        let locationProvider = MockLocationProvider()
        let service = LocationReportService(
            appStore: appStore,
            locationStateStore: stateStore,
            locationProvider: locationProvider
        )

        _ = try await service.manualReport(api: api)

        XCTAssertEqual(
            locationProvider.requestedSnapshotAccuracies,
            [LocationReportService.manualReportDesiredAccuracy]
        )
    }

    func testTooFrequentManualReportThrows() async throws {
        let reportJSON = """
        {"code":100000,"msg":"success","data":{"staff_id":"staff-1","expired":0,"status":1}}
        """.data(using: .utf8)!
        let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [reportJSON, reportJSON])))
        let stateStore = HomeLocationStateStore(store: appStore)
        let service = LocationReportService(appStore: appStore, locationStateStore: stateStore)

        _ = try await service.reportWithCoordinates(
            api: api,
            latitude: 30.0,
            longitude: 120.0,
            address: "测试地址",
            type: 1
        )
        do {
            _ = try await service.reportWithCoordinates(
                api: api,
                latitude: 30.0,
                longitude: 120.0,
                address: "测试地址",
                type: 1
            )
            XCTFail("Expected too frequent error")
        } catch let error as LocationReportServiceError {
            if case .tooFrequent = error {
                XCTAssertTrue(true)
            } else {
                XCTFail("Unexpected error \(error)")
            }
        }
    }

    func testMissingScenicThrows() async {
        appStore.session.currentScenicId = 0
        let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [])))
        let stateStore = HomeLocationStateStore(store: appStore)
        let service = LocationReportService(appStore: appStore, locationStateStore: stateStore)

        do {
            _ = try await service.manualReport(api: api)
            XCTFail("Expected missing scenic")
        } catch let error as LocationReportServiceError {
            XCTAssertEqual(error, .missingScenic)
        } catch {
            XCTFail("Unexpected error \(error)")
        }
    }
}
