//
//  ICCameraItem+CameraObjects.swift
//  otg_swift
//

import Foundation
@preconcurrency import ImageCaptureCore
import UniformTypeIdentifiers

/// 从 `ICCameraDevice` 设备树收集图片文件，并映射为通用 `CameraObject`。
enum ICCameraItemScanner {

    /// 多策略收集：`mediaFiles` → `contents` 递归 → `filesOfType(public.image)` 兜底。
    static func collectImageFiles(from device: ICCameraDevice, supplementalItems: [ICCameraItem] = []) -> [ICCameraFile] {
        var files = collectImageFilesFromDeviceTree(device)

        if files.isEmpty, !supplementalItems.isEmpty {
            files = collectImageFiles(from: supplementalItems)
            OTGLog.info(.connection, "collectImageFiles: using supplemental items, count=\(files.count)")
        }

        // 部分机型 contents 为空但 filesOfType 仍可枚举
        if files.isEmpty {
            files = collectImageFiles(fromFilesOfType: device)
        }

        return files
    }

    private static func collectImageFilesFromDeviceTree(_ device: ICCameraDevice) -> [ICCameraFile] {
        let mediaFiles = (device.mediaFiles ?? []).compactMap { $0 as? ICCameraFile }
        if !mediaFiles.isEmpty {
            return mediaFiles.filter { isImageFilename($0.name) }
        }
        return collectImageFiles(from: device.contents ?? [])
    }

    private static func collectImageFiles(fromFilesOfType device: ICCameraDevice) -> [ICCameraFile] {
        guard let names = device.files(ofType: UTType.image.identifier), !names.isEmpty else {
            return []
        }

        OTGLog.info(.connection, "filesOfType(public.image) count=\(names.count), preview=\(names.prefix(3))")

        let treeFiles = collectImageFiles(from: device.contents ?? [])
        if !treeFiles.isEmpty {
            return treeFiles.filter { file in
                guard let name = file.name else { return false }
                return names.contains(name) || names.contains(where: { ($0 as NSString).lastPathComponent == name })
            }
        }

        return []
    }

    /// 递归遍历文件夹，收集扩展名匹配的图片文件。
    static func collectImageFiles(from items: [ICCameraItem]) -> [ICCameraFile] {
        var results: [ICCameraFile] = []
        for item in items {
            if let file = item as? ICCameraFile, isImageFilename(file.name) {
                results.append(file)
            } else if let folder = item as? ICCameraFolder {
                results.append(contentsOf: collectImageFiles(from: folder.contents ?? []))
            }
        }
        return results
    }

    /// 按 `CameraObject.id`（文件名+大小）反查 ICCameraFile。
    static func findFile(matching object: CameraObject, in device: ICCameraDevice) -> ICCameraFile? {
        collectImageFiles(from: device).first { cameraObjectID(for: $0) == object.id }
    }

    static func cameraObject(from file: ICCameraFile) -> CameraObject? {
        guard let filename = file.name, !filename.isEmpty, isImageFilename(filename) else { return nil }
        let fileSize = Int64(file.fileSize)
        let capturedAt = file.exifCreationDate ?? file.fileCreationDate ?? file.creationDate ?? .distantPast
        return CameraObject(
            id: cameraObjectID(for: file),
            filename: filename,
            fileSize: fileSize,
            capturedAt: capturedAt
        )
    }

    /// 并发请求 metadata，补全 catalog 枚举阶段缺失的拍摄时间。
    static func cameraObjects(from files: [ICCameraFile]) async -> [CameraObject] {
        await withTaskGroup(of: (Int, CameraObject?).self) { group in
            for (index, file) in files.enumerated() {
                group.addTask {
                    (index, await cameraObject(from: file))
                }
            }

            var indexed = Array<CameraObject?>(repeating: nil, count: files.count)
            for await (index, object) in group {
                indexed[index] = object
            }
            return indexed.compactMap { $0 }
        }
    }

    static func cameraObject(from file: ICCameraFile) async -> CameraObject? {
        guard let filename = file.name, !filename.isEmpty, isImageFilename(filename) else { return nil }
        let fileSize = Int64(file.fileSize)
        let capturedAt = await ICCameraMetadataLoader.captureDate(from: file)
        return CameraObject(
            id: cameraObjectID(for: file),
            filename: filename,
            fileSize: fileSize,
            capturedAt: capturedAt
        )
    }

    /// 稳定 ID：文件名 + 文件大小（同目录重名不同尺寸可区分）。
    static func cameraObjectID(for file: ICCameraFile) -> String {
        cameraObjectID(filename: file.name ?? "unknown", fileSize: Int64(file.fileSize))
    }

    static func cameraObjectID(filename: String, fileSize: Int64) -> String {
        "\(filename)|\(fileSize)"
    }

    /// 从相册本地文件路径解析 dedup 键，与 `CameraObject.id` 格式一致。
    static func cameraObjectID(localPath: String) -> String? {
        guard !localPath.isEmpty,
              FileManager.default.fileExists(atPath: localPath) else { return nil }
        let filename = (localPath as NSString).lastPathComponent
        guard let attrs = try? FileManager.default.attributesOfItem(atPath: localPath),
              let size = attrs[.size] as? Int64 else { return nil }
        return cameraObjectID(filename: filename, fileSize: size)
    }

    static func isImageFilename(_ name: String?) -> Bool {
        guard let name else { return false }
        let ext = (name as NSString).pathExtension.lowercased()
        return ["jpg", "jpeg", "heic", "png", "arw", "cr2", "cr3", "nef", "raf"].contains(ext)
    }
}
