
import CoreImage
import Foundation

public class ImageUtility {
    enum ImageUtilityError: Error {
        case couldNotCreatePixelBuffer
    }

    public static func ciImage(_ url: URL?) -> CIImage? {
        guard
            let imageURL = url,
            let ciImage = CIImage(contentsOf: imageURL)
        else { return nil }
        return ciImage
    }

    public init() {}

    static func ciImageToCVPixelBuffer(_ ciImage: CIImage, size: CGSize) -> CVPixelBuffer? {
        var pixelBuffer: CVPixelBuffer?

        // Pixel buffer options
        let options: [String: Any] = [
            kCVPixelBufferCGImageCompatibilityKey as String: true,
            kCVPixelBufferCGBitmapContextCompatibilityKey as String: true,
        ]

        // Create pixel buffer
        let status = CVPixelBufferCreate(
            kCFAllocatorDefault,
            Int(size.width),
            Int(size.height),
            kCVPixelFormatType_32ARGB,
            options as CFDictionary,
            &pixelBuffer
        )

        guard status == kCVReturnSuccess, let buffer = pixelBuffer else {
            print("Error creating pixel buffer")
            return nil
        }

        // Lock the pixel buffer memory so it can be rendered into
        CVPixelBufferLockBaseAddress(buffer, [])

        // Create a CIContext for rendering
        let context = CIContext()

        // Render the CIImage into the pixel buffer
        context.render(ciImage, to: buffer)

        // Unlock the pixel buffer
        CVPixelBufferUnlockBaseAddress(buffer, [])

        return buffer
    }

    static func createPixelPuffer(size: CGSize) throws -> CVPixelBuffer? {
        var pixelBuffer: CVPixelBuffer?

        // Pixel buffer options
        let options: [String: Any] = [
            kCVPixelBufferCGImageCompatibilityKey as String: true,
            kCVPixelBufferCGBitmapContextCompatibilityKey as String: true,
        ]

        // Create pixel buffer
        let status = CVPixelBufferCreate(
            kCFAllocatorDefault,
            Int(size.width),
            Int(size.height),
            kCVPixelFormatType_32ARGB,
            options as CFDictionary,
            &pixelBuffer
        )

        guard status == kCVReturnSuccess, let buffer = pixelBuffer else {
            throw ImageUtilityError.couldNotCreatePixelBuffer
        }

        return buffer
    }
}
