//
//  CloudDriveListViewModel.swift
//  suixinkan
//

import Foundation

/// 云盘展示模式。
enum CloudDriveDisplayMode: Sendable, Equatable {
    case grid
    case list
}

/// 云盘文件排序方式。
enum CloudDriveSortType: Int, CaseIterable, Sendable {
    case createdAscending = 1
    case createdDescending = 2

    /// Android 对齐文案。
    var title: String {
        switch self {
        case .createdAscending:
            "创建时间顺序"
        case .createdDescending:
            "创建时间倒序"
        }
    }
}

/// 云盘文件类型筛选。
enum CloudDriveFilterType: Int, CaseIterable, Sendable {
    case all = 0
    case video = 1
    case image = 2
    case folder = 99

    /// Android 下拉菜单顺序。
    static let androidMenuOrder: [CloudDriveFilterType] = [.all, .image, .video, .folder]

    /// Android 下拉菜单文案。
    var menuTitle: String {
        switch self {
        case .all:
            "全部"
        case .video:
            "视频"
        case .image:
            "图片"
        case .folder:
            "文件夹"
        }
    }

    /// Android 筛选按钮当前值文案。
    var displayTitle: String {
        switch self {
        case .all:
            "全部"
        case .video:
            "视频"
        case .image:
            "文件"
        case .folder:
            "文件夹"
        }
    }
}

private struct CloudDriveCacheKey: Hashable {
    let folderId: Int
    let name: String
    let type: Int
    let orderBy: Int
}

private struct CloudDriveFolderCache {
    let list: [CloudFile]
    let total: Int
    let page: Int
}

/// 相册云盘列表 ViewModel，对齐 Android `CloudStorageListViewModel`。
final class CloudDriveListViewModel {
    private(set) var pathStack: [CloudPathItem] = [CloudPathItem(id: 0, name: "云盘")]
    private(set) var files: [CloudFile] = []
    private(set) var searchText = ""
    private(set) var filterType: CloudDriveFilterType = .all
    private(set) var sortType: CloudDriveSortType = .createdDescending
    private(set) var displayMode: CloudDriveDisplayMode = .grid
    private(set) var isLoading = false
    private(set) var isRefreshing = false
    private(set) var canLoadMore = false
    private(set) var currentControlFile: CloudFile?

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

    private var currentPage = 1
    private var totalCount = 0
    private let pageSize = 20
    private var folderCache: [CloudDriveCacheKey: CloudDriveFolderCache] = [:]
    private var dirtyFolders: Set<Int> = []

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

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

    /// 切换宫格/列表。
    func toggleDisplayMode() {
        displayMode = displayMode == .grid ? .list : .grid
        notifyStateChange()
    }

    /// 选择排序方式。
    func chooseSortType(_ type: CloudDriveSortType, api: any CloudDriveServing) async {
        sortType = type
        await refresh(api: api, showLoading: true)
    }

    /// 选择类型筛选。
    func chooseFilterType(_ type: CloudDriveFilterType, api: any CloudDriveServing) async {
        filterType = type
        await refresh(api: api, showLoading: true)
    }

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

    /// 加载更多。
    func loadMoreIfNeeded(lastVisibleIndex: Int, api: any CloudDriveServing) async {
        guard canLoadMore, !isLoading, lastVisibleIndex >= files.count - 6 else { return }
        currentPage += 1
        await loadPage(api: api, reset: false, showLoading: false)
    }

    /// 点击文件或文件夹。返回非文件夹供 UI 打开预览。
    func handleFileTap(_ file: CloudFile, api: any CloudDriveServing) async -> CloudFile? {
        if file.isFolder {
            searchText = ""
            pathStack.append(CloudPathItem(id: file.id, name: file.name))
            await refresh(api: api, showLoading: true)
            return nil
        }
        guard file.isSelectableMedia else { return nil }
        return file
    }

    /// 设置当前操作文件。
    func setControlFile(_ file: CloudFile) {
        currentControlFile = file
        notifyStateChange()
    }

    /// 返回上级目录；返回 false 时由 UI 执行 pop。
    func navigateBack(api: any CloudDriveServing) async -> Bool {
        guard pathStack.count > 1 else { return false }
        pathStack.removeLast()
        await restoreOrReload(api: api)
        return true
    }

    /// 回到云盘根目录。
    func goHome(api: any CloudDriveServing) async {
        pathStack = [pathStack.first ?? CloudPathItem(id: 0, name: "云盘")]
        await restoreOrReload(api: api)
    }

    /// 点击面包屑路径。
    func navigateToPathIndex(_ index: Int, api: any CloudDriveServing) async {
        guard index >= 0, index < pathStack.count else { return }
        pathStack = Array(pathStack.prefix(index + 1))
        await restoreOrReload(api: api)
    }

    /// 上传前检查权限。
    func checkCanUpload(api: any CloudDriveServing) async -> Bool {
        do {
            let response = try await api.checkUploadPermission()
            if !response.canUpload {
                onShowMessage?(response.reason)
            }
            return response.canUpload
        } catch {
            onShowMessage?(error.localizedDescription)
            return false
        }
    }

    /// 创建文件夹。
    func addFolder(name: String, api: any CloudDriveServing) async {
        let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmedName.isEmpty else {
            onShowMessage?("名称不能为空")
            return
        }
        guard pathStack.count < 5 else {
            onShowMessage?("不能创建更深的文件夹")
            return
        }
        await performLoading {
            try await api.createCloudFolder(parentFolderId: currentFolderID, name: trimmedName)
            invalidateFolderCache(currentFolderID)
            await refresh(api: api, showLoading: false)
        }
    }

    /// 删除当前操作文件。
    func deleteCurrentFile(api: any CloudDriveServing) async {
        guard let file = currentControlFile else { return }
        await performLoading {
            try await api.deleteCloudFiles(
                CloudFileDeleteRequest(list: [CloudFileOperationItem(id: file.id, type: file.type)])
            )
            invalidateFolderCache(currentFolderID)
            await refresh(api: api, showLoading: false)
        }
    }

    /// 移动当前操作文件。
    func moveCurrentFile(targetFolderId: Int, api: any CloudDriveServing) async {
        guard let file = currentControlFile else { return }
        await performLoading {
            try await api.moveCloudFiles(
                CloudFileMoveRequest(
                    targetFolderId: targetFolderId,
                    list: [CloudFileOperationItem(id: file.id, type: file.type)]
                )
            )
            invalidateFolderCache(currentFolderID)
            invalidateFolderCache(targetFolderId)
            await refresh(api: api, showLoading: false)
        }
    }

    /// 保存当前操作文件的名称。
    func saveCurrentFileName(_ name: String, api: any CloudDriveServing) async {
        guard let file = currentControlFile else { return }
        let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmedName.isEmpty else {
            onShowMessage?("名称不能为空")
            return
        }
        guard trimmedName != file.name else { return }
        await performLoading {
            if file.isFolder {
                try await api.modifyCloudFolderName(fileId: file.id, name: trimmedName)
            } else {
                try await api.modifyCloudFileName(fileId: file.id, fileName: trimmedName)
            }
            invalidateFolderCache(currentFolderID)
            await refresh(api: api, showLoading: false)
        }
    }

    /// 上传完成后标记目录需要刷新。
    func handleUploadCompleted(parentFolderId: Int, api: any CloudDriveServing) async {
        if parentFolderId == currentFolderID {
            invalidateFolderCache(parentFolderId)
            await refresh(api: api, showLoading: false)
        } else {
            invalidateFolderCache(parentFolderId)
        }
    }

    /// 当前目录可移动目标，与 Android 一致：根目录 + 当前列表内文件夹。
    func moveTargetFolders() -> [CloudFile] {
        let root = CloudFile(id: 0, name: "云盘", type: 99)
        let folders = files.filter { $0.isFolder }
        return ([root] + folders).reduce(into: [CloudFile]()) { result, item in
            guard !result.contains(where: { $0.id == item.id }) else { return }
            result.append(item)
        }
    }

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

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

    private func restoreOrReload(api: any CloudDriveServing) async {
        if dirtyFolders.remove(currentFolderID) != nil {
            await refresh(api: api, showLoading: true)
            return
        }
        if let cached = folderCache[currentKey()] {
            files = cached.list
            totalCount = cached.total
            currentPage = cached.page
            canLoadMore = files.count < totalCount
            notifyStateChange()
        } else {
            await refresh(api: api, showLoading: true)
        }
    }

    private func performLoading(_ operation: () async throws -> Void) async {
        isLoading = true
        notifyStateChange()
        defer {
            isLoading = false
            notifyStateChange()
        }
        do {
            try await operation()
        } catch is CancellationError {
            return
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    private func currentKey() -> CloudDriveCacheKey {
        CloudDriveCacheKey(
            folderId: currentFolderID,
            name: searchText,
            type: filterType.rawValue,
            orderBy: sortType.rawValue
        )
    }

    private func invalidateFolderCache(_ folderId: Int) {
        folderCache = folderCache.filter { $0.key.folderId != folderId }
        dirtyFolders.insert(folderId)
    }

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