//
//  BindAcquirerViewModelTests.swift
//  suixinkanTests
//
//  Created by Codex on 2026/7/3.
//

import XCTest
@testable import suixinkan

/// 绑定获客员 ViewModel 分账比例校验测试。
@MainActor
final class BindAcquirerViewModelTests: XCTestCase {
    /// 测试分账比例输入只保留数字且最多 3 位。
    func testUpdateCommissionRateDraftFiltersInput() {
        let viewModel = BindAcquirerViewModel()
        viewModel.updateCommissionRateDraft("12a3.4")
        XCTAssertEqual(viewModel.commissionRateDraft, "123")
        viewModel.updateCommissionRateDraft("1234")
        XCTAssertEqual(viewModel.commissionRateDraft, "123")
    }

    /// 测试未填写分账比例时提交失败。
    func testAcceptBindRequiresCommissionRate() async {
        let viewModel = BindAcquirerViewModel()
        let api = BindAcquirerMockAPI()
        await viewModel.load(api: api, saleUserId: 101)

        do {
            try await viewModel.acceptBind(api: api)
            XCTFail("Expected validation error")
        } catch let error as CooperationOrderCommissionRateValidationError {
            XCTAssertEqual(error.message, "请输入分账比例")
        } catch {
            XCTFail("Unexpected error: \(error)")
        }
        XCTAssertEqual(api.acceptBindCalls.count, 0)
    }

    /// 测试分账比例超出范围时提交失败。
    func testAcceptBindRejectsOutOfRangeCommissionRate() async {
        let viewModel = BindAcquirerViewModel()
        let api = BindAcquirerMockAPI()
        await viewModel.load(api: api, saleUserId: 101)
        viewModel.updateCommissionRateDraft("101")

        do {
            try await viewModel.acceptBind(api: api)
            XCTFail("Expected validation error")
        } catch let error as CooperationOrderCommissionRateValidationError {
            XCTAssertEqual(error.message, "分账比例需在0到100之间")
        } catch {
            XCTFail("Unexpected error: \(error)")
        }
        XCTAssertEqual(api.acceptBindCalls.count, 0)
    }

    /// 测试合法分账比例时调用 accept-bind 接口。
    func testAcceptBindPassesCommissionRateToAPI() async throws {
        let viewModel = BindAcquirerViewModel()
        let api = BindAcquirerMockAPI()
        await viewModel.load(api: api, saleUserId: 101)
        viewModel.updateCommissionRateDraft("20")

        try await viewModel.acceptBind(api: api)

        XCTAssertEqual(api.acceptBindCalls.count, 1)
        XCTAssertEqual(api.acceptBindCalls.first?.saleUserId, 101)
        XCTAssertEqual(api.acceptBindCalls.first?.commissionRate, 20)
    }
}

@MainActor
private final class BindAcquirerMockAPI: CooperationOrderServing {
    struct AcceptBindCall {
        let saleUserId: Int
        let commissionRate: Int
    }

    var acceptBindCalls: [AcceptBindCall] = []

    func cooperativeSalers(storeId: Int?, page: Int, pageSize: Int) async throws -> CooperativeSalerListPayload {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserInviteInfo(saleUserId: Int) async throws -> SaleUserInviteInfo {
        SaleUserInviteInfo(
            saleUserId: saleUserId,
            salerName: "测试获客员",
            salerPhone: "13800138000"
        )
    }

    func saleUserAcceptBind(saleUserId: Int, commissionRate: Int) async throws {
        acceptBindCalls.append(AcceptBindCall(saleUserId: saleUserId, commissionRate: commissionRate))
    }

    func saleUserReferralLeads(page: Int, pageSize: Int) async throws -> ListPayload<ReferralLead> {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserAcquisitionOrders(keyword: String?, page: Int, pageSize: Int) async throws -> ListPayload<AcquisitionOrder> {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserReferralOrders(saleUserId: Int, page: Int, pageSize: Int) async throws -> ReferralOrderListPayload {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserBindReferralOrder(orderNumber: String, referralOrderNo: String) async throws {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserUpdateReferralOrderStatus(id: Int, status: Int) async throws {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserUpdateRemark(saleUserId: Int, photogRemarkName: String) async throws {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserCommissionRateSendSmsCode(phone: String) async throws {
        fatalError("Not used in BindAcquirerViewModelTests")
    }

    func saleUserUpdateCommissionRate(
        saleUserId: Int,
        commissionRate: Int,
        smsCode: String
    ) async throws -> CooperativeSaler {
        fatalError("Not used in BindAcquirerViewModelTests")
    }
}
