//
//  PunchPointAPITests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

/// 打卡点管理 API 路径、参数与请求体测试。
@MainActor
final class PunchPointAPITests: XCTestCase {
    func testListAndInfoUseAndroidPathsAndQueries() async throws {
        let session = MockURLSession(responses: [
            envelopeJSON(#"{"total":0,"list":[]}"#),
            envelopeJSON(#"{"id":18,"name":"观景台"}"#),
        ])
        let api = PunchPointAPI(client: APIClient(environment: .testing, session: session))

        _ = try await api.list(scenicAreaId: "9", status: 2, page: 3, pageSize: 10)
        _ = try await api.info(id: 18)

        XCTAssertEqual(session.requests[0].httpMethod, "GET")
        XCTAssertEqual(session.requests[0].url?.path, "/api/yf-handset-app/photog/scenic-spot/list")
        let listQuery = URLComponents(url: try XCTUnwrap(session.requests[0].url), resolvingAgainstBaseURL: false)?.queryItems
        XCTAssertEqual(listQuery?.first { $0.name == "scenic_area_id" }?.value, "9")
        XCTAssertEqual(listQuery?.first { $0.name == "status" }?.value, "2")
        XCTAssertEqual(listQuery?.first { $0.name == "page" }?.value, "3")
        XCTAssertEqual(listQuery?.first { $0.name == "page_size" }?.value, "10")

        XCTAssertEqual(session.requests[1].httpMethod, "GET")
        XCTAssertEqual(session.requests[1].url?.path, "/api/yf-handset-app/photog/scenic-spot/info")
        let infoQuery = URLComponents(url: try XCTUnwrap(session.requests[1].url), resolvingAgainstBaseURL: false)?.queryItems
        XCTAssertEqual(infoQuery?.first { $0.name == "id" }?.value, "18")
    }

    func testAddEditAndDeleteEncodeAndroidBodies() async throws {
        let session = MockURLSession(responses: [envelopeJSON("{}"), envelopeJSON("{}"), envelopeJSON("{}")])
        let api = PunchPointAPI(client: APIClient(environment: .testing, session: session))
        let addRequest = PunchPointSaveRequest(
            scenicAreaId: "7",
            name: "山顶打卡点",
            description: "日出位置",
            region: PunchPointSaveRegion(lot: 120.12, lat: 30.23, address: "山顶平台"),
            scenicSpotString: "山顶平台",
            guideImages: ["https://cdn/a.jpg"]
        )
        let editRequest = PunchPointSaveRequest(
            id: 88,
            scenicAreaId: "7",
            name: "山顶打卡点2",
            description: nil,
            region: PunchPointSaveRegion(lot: 121.12, lat: 31.23, address: "新平台"),
            scenicSpotString: "新平台",
            guideImages: ["https://cdn/b.jpg"]
        )

        try await api.add(addRequest)
        try await api.edit(editRequest)
        try await api.delete(id: 88)

        XCTAssertEqual(session.requests[0].url?.path, "/api/yf-handset-app/photog/scenic-spot/add")
        let addBody = try bodyJSON(session.requests[0])
        XCTAssertNil(addBody["id"])
        XCTAssertEqual(addBody["scenic_area_id"] as? String, "7")
        XCTAssertEqual(addBody["name"] as? String, "山顶打卡点")
        XCTAssertEqual(addBody["scenic_spot_str"] as? String, "山顶平台")
        XCTAssertEqual(addBody["guide_imgs"] as? [String], ["https://cdn/a.jpg"])
        let addRegion = try XCTUnwrap(addBody["region"] as? [String: Any])
        XCTAssertEqual(addRegion["lot"] as? Double, 120.12)
        XCTAssertEqual(addRegion["lat"] as? Double, 30.23)
        XCTAssertEqual(addRegion["address"] as? String, "山顶平台")

        XCTAssertEqual(session.requests[1].url?.path, "/api/yf-handset-app/photog/scenic-spot/edit")
        let editBody = try bodyJSON(session.requests[1])
        XCTAssertEqual(editBody["id"] as? Int, 88)
        XCTAssertEqual(editBody["name"] as? String, "山顶打卡点2")
        XCTAssertNil(editBody["description"])

        XCTAssertEqual(session.requests[2].url?.path, "/api/yf-handset-app/photog/scenic-spot/delete")
        let deleteBody = try bodyJSON(session.requests[2])
        XCTAssertEqual(deleteBody["id"] as? Int, 88)
    }

    private func envelopeJSON(_ dataJSON: String) -> Data {
        """
        {"code":100000,"msg":"success","data":\(dataJSON)}
        """.data(using: .utf8)!
    }

    private func bodyJSON(_ request: URLRequest) throws -> [String: Any] {
        try XCTUnwrap(JSONSerialization.jsonObject(with: try XCTUnwrap(request.httpBody)) as? [String: Any])
    }
}
