//
//  CommissionRateLogTests.swift
//  suixinkanTests
//

import UIKit
import XCTest
@testable import suixinkan

/// 获客员分成比例修改记录模型、接口与分页行为测试。
@MainActor
final class CommissionRateLogTests: XCTestCase {
    func testModelDecodesCompleteRecordAndBuildsBusinessDisplayText() throws {
        let data = """
        {
          "list": [{
            "id": 1,
            "binding_id": 10,
            "sale_user_id": 456,
            "store_user_id": 732,
            "before_rate": 10,
            "before_rate_label": "10%（旧）",
            "after_rate": 20,
            "after_rate_label": "20%（新）",
            "operator_type": "store_user",
            "operator_id": 732,
            "operator_name": "李师傅",
            "remark": "  调整合作比例  ",
            "created_at": "2026-07-23 11:00:00"
          }],
          "total": 1,
          "page": 1,
          "page_size": 10
        }
        """.data(using: .utf8)!

        let response = try JSONDecoder().decode(CommissionRateLogListResponse.self, from: data)
        let item = try XCTUnwrap(response.list.first)

        XCTAssertEqual(response.pageSize, 10)
        XCTAssertEqual(item.bindingId, 10)
        XCTAssertEqual(item.saleUserId, 456)
        XCTAssertEqual(item.storeUserId, 732)
        XCTAssertEqual(item.operatorType, "store_user")
        XCTAssertEqual(item.operatorId, 732)
        XCTAssertEqual(item.displayBeforeRate, "10%（旧）")
        XCTAssertEqual(item.displayAfterRate, "20%（新）")
        XCTAssertEqual(item.metadataLine, "2026-07-23 11:00")
        XCTAssertEqual(item.displayRemark, "调整合作比例")
    }

    func testDisplayFallsBackToNumericRateUnknownOperatorAndRawTime() throws {
        let data = """
        {
          "list": [{
            "id": 2,
            "binding_id": 0,
            "sale_user_id": 456,
            "store_user_id": 0,
            "before_rate": 5,
            "before_rate_label": "",
            "after_rate": 15,
            "after_rate_label": " ",
            "operator_type": "",
            "operator_id": 0,
            "operator_name": "",
            "remark": " ",
            "created_at": "服务端时间"
          }],
          "total": 1,
          "page": 1,
          "page_size": 10
        }
        """.data(using: .utf8)!

        let item = try JSONDecoder().decode(CommissionRateLogListResponse.self, from: data).list[0]

        XCTAssertEqual(item.displayBeforeRate, "5%")
        XCTAssertEqual(item.displayAfterRate, "15%")
        XCTAssertEqual(item.metadataLine, "服务端时间")
        XCTAssertNil(item.displayRemark)
    }

    func testAPIBuildsPathAndClampsPaginationParameters() async throws {
        let session = MockURLSession(responses: [envelope(list: [], total: 0, page: 1)])
        let api = OrderAPI(client: APIClient(environment: .testing, session: session))

        _ = try await api.saleUserCommissionRateLogs(saleUserId: 456, page: 0, pageSize: 99)

        let request = try XCTUnwrap(session.requests.first)
        XCTAssertEqual(request.httpMethod, "GET")
        XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/sale-user/commission-rate/logs")
        let query = URLComponents(url: try XCTUnwrap(request.url), resolvingAgainstBaseURL: false)?.queryItems
        XCTAssertEqual(query?.first { $0.name == "sale_user_id" }?.value, "456")
        XCTAssertEqual(query?.first { $0.name == "page" }?.value, "1")
        XCTAssertEqual(query?.first { $0.name == "page_size" }?.value, "50")
    }

    func testViewModelRetriesFailedPageAndDeduplicatesItems() async throws {
        let page1 = envelope(
            list: [
                record(id: 1, before: 10, after: 20),
                record(id: 1, before: 10, after: 20),
                record(id: 2, before: 20, after: 30),
            ],
            total: 3,
            page: 1
        )
        let page2 = envelope(
            list: [
                record(id: 2, before: 20, after: 30),
                record(id: 3, before: 30, after: 40),
            ],
            total: 3,
            page: 2
        )
        let response = HTTPURLResponse(
            url: URL(string: "https://api-test.zhifly.cn/mock")!,
            statusCode: 200,
            httpVersion: nil,
            headerFields: nil
        )!
        let session = MockURLSession(results: [
            .success((page1, response)),
            .failure(URLError(.timedOut)),
            .success((page2, response)),
        ])
        let api = OrderAPI(client: APIClient(environment: .testing, session: session))
        let viewModel = CommissionRateLogViewModel(saleUserId: 456)

        await viewModel.refresh(api: api)
        await viewModel.loadMore(api: api)

        XCTAssertEqual(viewModel.items.map(\.id), [1, 2])
        XCTAssertTrue(viewModel.canLoadMore)
        XCTAssertFalse(viewModel.isLoadingMore)

        await viewModel.loadMore(api: api)

        XCTAssertEqual(viewModel.items.map(\.id), [1, 2, 3])
        XCTAssertFalse(viewModel.canLoadMore)
        let requestedPages = session.requests.compactMap { request in
            URLComponents(url: request.url!, resolvingAgainstBaseURL: false)?
                .queryItems?
                .first { $0.name == "page" }?
                .value
        }
        XCTAssertEqual(requestedPages, ["1", "2", "2"])
    }

    func testTimelineCellOnlyMarksLatestRecord() {
        let item = CommissionRateLogEntity(
            id: 1,
            bindingId: 10,
            saleUserId: 456,
            storeUserId: 732,
            beforeRate: 10,
            beforeRateLabel: "10%",
            afterRate: 20,
            afterRateLabel: "20%",
            operatorType: "store_user",
            operatorId: 732,
            operatorName: "李师傅",
            remark: "",
            createdAt: "2026-07-23 11:00:00"
        )
        let cell = CommissionRateLogTimelineCell(style: .default, reuseIdentifier: nil)

        cell.configure(with: item, isLatest: true)
        XCTAssertTrue(cell.accessibilityLabel?.contains("最新记录") == true)
        XCTAssertFalse(cell.accessibilityLabel?.contains("李师傅") == true)

        cell.configure(with: item, isLatest: false)
        XCTAssertFalse(cell.accessibilityLabel?.contains("最新记录") == true)
    }

    func testPageTitleUsesAcquirerNameAndFallsBackWhenEmpty() {
        let namedController = CommissionRateLogViewController(
            saleUserId: 456,
            acquirerName: " 获客员小王 "
        )
        namedController.setupNavigationBar()
        XCTAssertEqual(namedController.title, "给获客员小王的分成记录")

        let fallbackController = CommissionRateLogViewController(
            saleUserId: 456,
            acquirerName: " "
        )
        fallbackController.setupNavigationBar()
        XCTAssertEqual(fallbackController.title, "修改记录")
    }

    func testAcquirerCardUsesUnifiedActionsAndBusinessHierarchy() throws {
        let cell = CooperationAcquirerCell(style: .default, reuseIdentifier: nil)
        cell.configure(
            with: CooperativeSalerEntity(
                saleUserId: 456,
                name: "获客员小王",
                salerPhone: "13800138000",
                commissionRate: 20,
                commissionRateLabel: "20%",
                bindTime: "2026-07-23 11:00:00"
            )
        )
        let fittingSize = cell.contentView.systemLayoutSizeFitting(
            CGSize(width: 390, height: UIView.layoutFittingCompressedSize.height),
            withHorizontalFittingPriority: .required,
            verticalFittingPriority: .fittingSizeLevel
        )
        cell.frame = CGRect(x: 0, y: 0, width: 390, height: fittingSize.height)
        cell.layoutIfNeeded()

        let remarkButton = try XCTUnwrap(
            subview(in: cell, identifier: "cooperation_acquirer_edit_remark") as? UIButton
        )
        let logButton = try XCTUnwrap(
            subview(in: cell, identifier: "cooperation_acquirer_commission_logs") as? UIButton
        )
        let commissionButton = try XCTUnwrap(
            subview(in: cell, identifier: "cooperation_acquirer_edit_commission") as? UIButton
        )
        let bindTimeLabel = try XCTUnwrap(
            subview(in: cell, identifier: "cooperation_acquirer_bind_time") as? UILabel
        )

        XCTAssertEqual(remarkButton.bounds.height, AppSpacing.minTouchTarget, accuracy: 0.5)
        XCTAssertEqual(logButton.bounds.height, remarkButton.bounds.height, accuracy: 0.5)
        XCTAssertEqual(commissionButton.bounds.height, remarkButton.bounds.height, accuracy: 0.5)
        XCTAssertEqual(logButton.bounds.width, remarkButton.bounds.width, accuracy: 0.5)
        XCTAssertEqual(commissionButton.bounds.width, remarkButton.bounds.width, accuracy: 0.5)
        XCTAssertEqual(bindTimeLabel.text, "绑定于 2026-07-23 11:00")
    }

    private func envelope(list: [[String: Any]], total: Int, page: Int) -> Data {
        let object: [String: Any] = [
            "code": 100000,
            "msg": "success",
            "data": [
                "list": list,
                "total": total,
                "page": page,
                "page_size": 10,
            ],
        ]
        return try! JSONSerialization.data(withJSONObject: object)
    }

    private func record(id: Int, before: Int, after: Int) -> [String: Any] {
        [
            "id": id,
            "binding_id": 10,
            "sale_user_id": 456,
            "store_user_id": 732,
            "before_rate": before,
            "before_rate_label": "\(before)%",
            "after_rate": after,
            "after_rate_label": "\(after)%",
            "operator_type": "store_user",
            "operator_id": 732,
            "operator_name": "李师傅",
            "remark": "",
            "created_at": "2026-07-23 11:00:00",
        ]
    }

    private func subview(in root: UIView, identifier: String) -> UIView? {
        if root.accessibilityIdentifier == identifier {
            return root
        }
        for child in root.subviews {
            if let match = subview(in: child, identifier: identifier) {
                return match
            }
        }
        return nil
    }
}
