//
//  CloudStoragePickForTaskViewModel.swift
//  suixinkan
//

import Foundation

/// 任务云盘多选 ViewModel，对齐 Android 任务模式云盘浏览与多选逻辑。
final class CloudStoragePickForTaskViewModel {

    private(set) var pathStack: [CloudPathItem] = [CloudPathItem(id: 0, name: "全部文件")]
    private(set) var files: [CloudFile] = []
    private(set) var selectedFiles: [Int: CloudFile] = [:]
    private(set) var searchText = ""
    private(set) var filterType = 0
    private(set) var sortType = 2
    private(set) var isLoading = false
    private(set) var isRefreshing = false
    private(set) var canLoadMore = false

    var onStateChange: (() -> Void)?
    var onShowMessage: ((String) -> Void)?

    private var currentPage = 1
    private var totalCount = 0
    private let pageSize = 20
    private let importedFileIDs: Set<Int>
    private let allowedFileType: Int?

    /// 初始化云盘多选 ViewModel，可按云盘文件类型限制选择范围。
    init(importedFileIDs: Set<Int> = [], allowedFileType: Int? = nil) {
        self.importedFileIDs = importedFileIDs
        self.allowedFileType = allowedFileType
        self.filterType = allowedFileType ?? 0
    }

    /// 当前文件夹 ID。
    var currentFolderID: Int {
        pathStack.last?.id ?? 0
    }

    /// 已选文件列表。
    var selectedFileList: [CloudFile] {
        Array(selectedFiles.values)
    }

    /// 文件是否已在任务页导入。
    func isImported(_ fileID: Int) -> Bool {
        importedFileIDs.contains(fileID)
    }

    /// 文件是否已选中。
    func isSelected(_ fileID: Int) -> Bool {
        selectedFiles[fileID] != nil
    }

    /// 更新搜索词。
    func updateSearchText(_ text: String) {
        searchText = text
        notifyStateChange()
    }

    /// 更新类型筛选。
    func updateFilterType(_ type: Int) {
        filterType = type
        notifyStateChange()
    }

    /// 更新排序方式。
    func updateSortType(_ type: Int) {
        sortType = type
        notifyStateChange()
    }

    /// 首次或刷新加载。
    func refresh(api: TaskAPI) async {
        currentPage = 1
        isRefreshing = true
        notifyStateChange()
        await loadPage(api: api, reset: true)
        isRefreshing = false
        notifyStateChange()
    }

    /// 加载更多。
    func loadMore(api: TaskAPI) async {
        guard canLoadMore, !isLoading else { return }
        currentPage += 1
        await loadPage(api: api, reset: false)
    }

    /// 点击文件或文件夹。
    func handleItemTap(_ file: CloudFile, api: TaskAPI) async {
        if file.isFolder {
            pathStack.append(CloudPathItem(id: file.id, name: file.name))
            searchText = ""
            await refresh(api: api)
            return
        }
        guard file.isSelectableMedia else { return }
        if let allowedFileType, file.type != allowedFileType {
            onShowMessage?(allowedFileType == 1 ? "请选择视频素材" : "请选择图片素材")
            return
        }
        if isImported(file.id) {
            onShowMessage?("已选择")
            return
        }
        if selectedFiles[file.id] != nil {
            selectedFiles.removeValue(forKey: file.id)
        } else {
            selectedFiles[file.id] = file
        }
        notifyStateChange()
    }

    /// 跳转面包屑路径。
    func navigateToPathIndex(_ index: Int, api: TaskAPI) async {
        guard index >= 0, index < pathStack.count else { return }
        pathStack = Array(pathStack.prefix(index + 1))
        searchText = ""
        await refresh(api: api)
    }

    /// 返回上级目录。
    func navigateBack(api: TaskAPI) async -> Bool {
        guard pathStack.count > 1 else { return false }
        pathStack.removeLast()
        searchText = ""
        await refresh(api: api)
        return true
    }

    private func loadPage(api: TaskAPI, reset: Bool) async {
        isLoading = true
        notifyStateChange()
        defer {
            isLoading = false
            notifyStateChange()
        }

        do {
            let response = try await api.cloudFileList(
                parentFolderId: currentFolderID,
                name: searchText,
                type: filterType,
                orderBy: sortType,
                page: currentPage,
                pageSize: pageSize
            )
            totalCount = response.total
            if reset {
                files = response.list
            } else {
                files.append(contentsOf: response.list)
            }
            canLoadMore = files.count < totalCount
        } catch is CancellationError {
            return
        } catch {
            if reset {
                files = []
            }
            canLoadMore = false
            onShowMessage?(error.localizedDescription)
        }
    }

    private func notifyStateChange() {
        onStateChange?()
    }
}
