//
//  CloudStoragePickForTaskViewModelTests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

@MainActor
/// 任务云盘多选 ViewModel 测试。
final class CloudStoragePickForTaskViewModelTests: XCTestCase {

    func testHandleItemTapTogglesMediaSelection() async throws {
        let listJSON = try makeListJSON(files: [
            makeFileJSON(id: 5, name: "图片", type: 2),
        ])
        let api = makeAPI(responses: [listJSON, listJSON])
        let viewModel = CloudStoragePickForTaskViewModel()
        await viewModel.refresh(api: api)
        let file = try XCTUnwrap(viewModel.files.first)

        await viewModel.handleItemTap(file, api: api)
        XCTAssertTrue(viewModel.isSelected(5))

        await viewModel.handleItemTap(file, api: api)
        XCTAssertFalse(viewModel.isSelected(5))
    }

    func testHandleItemTapShowsImportedMessage() async throws {
        let listJSON = try makeListJSON(files: [
            makeFileJSON(id: 5, name: "图片", type: 2),
        ])
        let api = makeAPI(responses: [listJSON])
        let viewModel = CloudStoragePickForTaskViewModel(importedFileIDs: [5])
        var message: String?
        viewModel.onShowMessage = { message = $0 }
        await viewModel.refresh(api: api)
        let file = try XCTUnwrap(viewModel.files.first)

        await viewModel.handleItemTap(file, api: api)

        XCTAssertEqual(message, "已选择")
        XCTAssertFalse(viewModel.isSelected(5))
    }

    func testNavigateToFolderUpdatesPathStack() async throws {
        let rootJSON = try makeListJSON(files: [
            makeFileJSON(id: 8, name: "文件夹", type: 99),
        ])
        let childJSON = try makeListJSON(files: [])
        let api = makeAPI(responses: [rootJSON, childJSON])
        let viewModel = CloudStoragePickForTaskViewModel()
        await viewModel.refresh(api: api)
        let folder = try XCTUnwrap(viewModel.files.first)

        await viewModel.handleItemTap(folder, api: api)

        XCTAssertEqual(viewModel.pathStack.map(\.id), [0, 8])
    }

    func testSelectedFileListReturnsAllChosenFiles() async throws {
        let listJSON = try makeListJSON(files: [
            makeFileJSON(id: 1, name: "A", type: 2),
            makeFileJSON(id: 2, name: "B", type: 2),
        ])
        let api = makeAPI(responses: [listJSON, listJSON, listJSON])
        let viewModel = CloudStoragePickForTaskViewModel()
        await viewModel.refresh(api: api)

        await viewModel.handleItemTap(viewModel.files[0], api: api)
        await viewModel.handleItemTap(viewModel.files[1], api: api)

        XCTAssertEqual(Set(viewModel.selectedFileList.map(\.id)), Set([1, 2]))
    }

    func testAllowedFileTypeRejectsMismatchedMedia() async throws {
        let listJSON = try makeListJSON(files: [
            makeFileJSON(id: 1, name: "视频", type: 1),
            makeFileJSON(id: 2, name: "图片", type: 2),
        ])
        let api = makeAPI(responses: [listJSON])
        let viewModel = CloudStoragePickForTaskViewModel(allowedFileType: 2)
        var message: String?
        viewModel.onShowMessage = { message = $0 }
        await viewModel.refresh(api: api)

        await viewModel.handleItemTap(viewModel.files[0], api: api)
        await viewModel.handleItemTap(viewModel.files[1], api: api)

        XCTAssertEqual(message, "请选择图片素材")
        XCTAssertFalse(viewModel.isSelected(1))
        XCTAssertTrue(viewModel.isSelected(2))
    }

    private func makeAPI(responses: [Data]) -> TaskAPI {
        TaskAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: responses)))
    }

    private func makeListJSON(files: [[String: Any]]) throws -> Data {
        let listData = try JSONSerialization.data(withJSONObject: files)
        let listObject = try JSONSerialization.jsonObject(with: listData)
        let envelope: [String: Any] = [
            "code": 100000,
            "msg": "success",
            "data": [
                "total": files.count,
                "list": listObject,
            ],
        ]
        return try JSONSerialization.data(withJSONObject: envelope)
    }

    private func makeFileJSON(id: Int, name: String, type: Int) -> [String: Any] {
        [
            "id": id,
            "parent_folder_id": 0,
            "file_url": "https://cdn/\(id).jpg",
            "cover_url": "",
            "updated_at": "",
            "name": name,
            "created_at": "",
            "child_num": 0,
            "type": type,
            "file_size": 100,
        ]
    }
}
