import Foundation
import UIKit

enum FileVaultError: Error {
    case readFailed
    case writeFailed
    case removeFailed
    case decodeFailed
}

/// `@unchecked Sendable`:rootURL 是 let,方法只 I/O 到沙盒目录(线程安全),
/// 可被任意 actor / Task 跨边界访问。实例方法显式 `nonisolated`,见 ModelStore 同款注释。
final class FileVault: @unchecked Sendable {
    nonisolated static let shared: FileVault = {
        do {
            let appSupport = try FileManager.default.url(
                for: .applicationSupportDirectory,
                in: .userDomainMask,
                appropriateFor: nil,
                create: true
            )
            let vaultURL = appSupport.appendingPathComponent("Vault", isDirectory: true)
            return try FileVault(rootURL: vaultURL)
        } catch {
            fatalError("FileVault.shared init failed: \(error)")
        }
    }()

    let rootURL: URL

    init(rootURL: URL) throws {
        self.rootURL = rootURL
        try FileManager.default.createDirectory(
            at: rootURL,
            withIntermediateDirectories: true,
            attributes: [.protectionKey: FileProtectionType.complete]
        )
    }

    struct SavedAsset {
        let relativePath: String
        let bytes: Int
    }

    // MARK: - Path Safety

    nonisolated private func resolveSafePath(_ relativePath: String) throws -> URL {
        guard !relativePath.contains("/"),
              !relativePath.contains(".."),
              !relativePath.isEmpty else {
            throw FileVaultError.readFailed
        }
        let url = rootURL.appendingPathComponent(relativePath)
        guard url.path.hasPrefix(rootURL.path) else {
            throw FileVaultError.readFailed
        }
        return url
    }

    // MARK: - Public API

    nonisolated func writeJPEG(_ image: UIImage, quality: CGFloat = 0.85) throws -> SavedAsset {
        guard let data = image.jpegData(compressionQuality: quality) else {
            throw FileVaultError.writeFailed
        }
        let filename = "\(UUID().uuidString).jpg"
        let url = rootURL.appendingPathComponent(filename)
        try data.write(to: url, options: [.atomic, .completeFileProtection])
        return SavedAsset(relativePath: filename, bytes: data.count)
    }

    nonisolated func loadImage(relativePath: String) throws -> UIImage {
        let url = try resolveSafePath(relativePath)
        let data: Data
        do {
            data = try Data(contentsOf: url)
        } catch {
            throw FileVaultError.readFailed
        }
        guard let image = UIImage(data: data) else { throw FileVaultError.decodeFailed }
        return image
    }

    nonisolated func remove(relativePath: String) throws {
        let url = try resolveSafePath(relativePath)
        do {
            try FileManager.default.removeItem(at: url)
        } catch {
            throw FileVaultError.removeFailed
        }
    }

    nonisolated func wipe() throws {
        let fm = FileManager.default
        let contents = try fm.contentsOfDirectory(at: rootURL, includingPropertiesForKeys: nil)
        for url in contents {
            try fm.removeItem(at: url)
        }
    }
}
