//
//  MessageCenterAPITests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

/// 消息中心 API 路径、参数与模型解码测试。
@MainActor
final class MessageCenterAPITests: XCTestCase {
    func testListBuildsAndroidQueryAndDecodesMessagePayload() async throws {
        let payload = """
        {
          "has_more": true,
          "last_id": 18,
          "is_refresh": false,
          "items": [{
            "id": 21,
            "receiver_id": 9,
            "receiver_type": "staff",
            "type": 2,
            "type_name": "退款成功通知",
            "title": "unused",
            "content": "退款已完成",
            "push_at": "2026-07-09 10:00:00",
            "is_read": false,
            "read_at": "",
            "push_channel": 1,
            "push_channel_name": "站内信",
            "extra_data": {"order_no":"NO123","amount":12.5},
            "created_at": "2026-07-09 10:00:00",
            "updated_at": "2026-07-09 10:01:00"
          }]
        }
        """
        let session = MockURLSession(responses: [envelopeJSON(payload)])
        let api = MessageCenterAPI(client: APIClient(environment: .testing, session: session))

        let response = try await api.list(lastId: 7, limit: 20, unread: 0)

        let request = try XCTUnwrap(session.requests.first)
        XCTAssertEqual(request.httpMethod, "GET")
        XCTAssertEqual(request.url?.path, "/api/app/msg/list")
        let query = URLComponents(url: try XCTUnwrap(request.url), resolvingAgainstBaseURL: false)?.queryItems
        XCTAssertEqual(query?.first { $0.name == "last_id" }?.value, "7")
        XCTAssertEqual(query?.first { $0.name == "limit" }?.value, "20")
        XCTAssertEqual(query?.first { $0.name == "unread" }?.value, "0")
        XCTAssertTrue(response.hasMore)
        XCTAssertEqual(response.lastId, 18)
        XCTAssertEqual(response.items.first?.id, 21)
        XCTAssertEqual(response.items.first?.isRead, false)
        XCTAssertEqual(response.items.first?.extraData?["order_no"], .string("NO123"))
    }

    func testUnreadCountReadAllReadAndDeleteUseExpectedContracts() async throws {
        let session = MockURLSession(responses: [
            envelopeJSON(#"{"unread_count":"12"}"#),
            envelopeJSON(#"{"unread_count":11}"#),
            envelopeJSON(#"{"updated_count":11,"unread_count":0}"#),
            envelopeJSON("{}"),
        ])
        let api = MessageCenterAPI(client: APIClient(environment: .testing, session: session))

        let unread = try await api.unreadCount()
        let read = try await api.markAsRead(messageId: 21)
        let readAll = try await api.markAllAsRead()
        try await api.delete(messageId: 21)

        XCTAssertEqual(unread.unreadCount, 12)
        XCTAssertEqual(session.requests[0].httpMethod, "GET")
        XCTAssertEqual(session.requests[0].url?.path, "/api/app/msg/unread-count")

        XCTAssertEqual(read.unreadCount, 11)
        XCTAssertEqual(session.requests[1].httpMethod, "POST")
        XCTAssertEqual(session.requests[1].url?.path, "/api/app/msg/read")
        let readQuery = URLComponents(url: try XCTUnwrap(session.requests[1].url), resolvingAgainstBaseURL: false)?.queryItems
        XCTAssertEqual(readQuery?.first { $0.name == "id" }?.value, "21")

        XCTAssertEqual(readAll, MessageReadAllResponse(updatedCount: 11, unreadCount: 0))
        XCTAssertEqual(session.requests[2].httpMethod, "POST")
        XCTAssertEqual(session.requests[2].url?.path, "/api/app/msg/read-all")

        XCTAssertEqual(session.requests[3].httpMethod, "POST")
        XCTAssertEqual(session.requests[3].url?.path, "/api/app/msg/delete")
        let deleteBody = try bodyJSON(session.requests[3])
        XCTAssertEqual(deleteBody["id"] as? Int, 21)
    }

    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])
    }
}
