//
//  ProfileEditViewModelTests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

@MainActor
/// 资料编辑页 ViewModel 测试。
final class ProfileEditViewModelTests: XCTestCase {

    func testInitPrefillsNicknameWhenSet() {
        let viewModel = ProfileEditViewModel(nickname: "测试昵称", avatarURL: "https://example.com/a.jpg")
        XCTAssertEqual(viewModel.editingNickname, "测试昵称")
    }

    func testInitClearsPlaceholderNickname() {
        let viewModel = ProfileEditViewModel(nickname: "未设置昵称", avatarURL: "")
        XCTAssertEqual(viewModel.editingNickname, "")
    }

    func testSaveProfileRejectsEmptyNickname() async {
        let viewModel = ProfileEditViewModel(nickname: "未设置昵称", avatarURL: "")
        let session = MockURLSession(responses: [])
        let api = ProfileAPI(client: APIClient(environment: .testing, session: session))

        do {
            try await viewModel.saveProfile(
                api: api,
                uploader: MockOSSUploadService(),
                scenicId: 1
            )
            XCTFail("空昵称应抛出校验错误")
        } catch {
            guard let validationError = error as? ProfileValidationError else {
                return XCTFail("期望 ProfileValidationError，实际为 \(error)")
            }
            XCTAssertEqual(validationError, .emptyNickname)
        }
    }

    func testSaveProfilePostsNotificationAndUpdatesAppStore() async throws {
        let viewModel = ProfileEditViewModel(nickname: "旧昵称", avatarURL: "")
        viewModel.updateEditingNickname("新昵称")

        let expectation = expectation(forNotification: NotificationName.userProfileDidUpdate, object: nil)

        let responseData = try TestJSON.envelope(data: EmptyPayload())
        let session = MockURLSession(responses: [responseData])
        let api = ProfileAPI(client: APIClient(environment: .testing, session: session))

        try await viewModel.saveProfile(
            api: api,
            uploader: MockOSSUploadService(),
            scenicId: 1
        )

        await fulfillment(of: [expectation], timeout: 1)
        XCTAssertEqual(AppStore.shared.session.userName, "新昵称")
    }
}

/// 测试用 OSS 上传替身，直接返回固定 URL。
@MainActor
private struct MockOSSUploadService: OSSUploadServing {
    func uploadUserAvatar(
        data: Data,
        fileName: String,
        scenicId: Int,
        onProgress: @escaping (Int) -> Void
    ) async throws -> String {
        onProgress(100)
        return "https://cdn.example.com/avatar.jpg"
    }

    func uploadRealNameImage(
        data: Data,
        fileName: String,
        scenicId: Int,
        onProgress: @escaping (Int) -> Void
    ) async throws -> String {
        onProgress(100)
        return "https://cdn.example.com/realname.jpg"
    }

    func uploadBankCardImage(
        data: Data,
        fileName: String,
        scenicId: Int,
        onProgress: @escaping (Int) -> Void
    ) async throws -> String {
        onProgress(100)
        return "https://cdn.example.com/bank.jpg"
    }
}
