//
//  ImageGrayscalifier.swift
//  Tusker
//
//  Created by Shadowfacts on 10/29/20.
//  Copyright © 2020 Shadowfacts. All rights reserved.
//

import UIKit

struct ImageGrayscalifier {
    static let queue = DispatchQueue(label: "ImageGrayscalifier", qos: .userInitiated)
    
    private static let context = CIContext()
    private static let cache = NSCache<NSURL, UIImage>()

    static func convertIfNecessary(url: URL?, image: UIImage) -> UIImage? {
        if Preferences.shared.grayscaleImages,
           let source = image.cgImage {
            // todo: should this return the original image if conversion fails?
            return convert(url: url, cgImage: source)
        } else {
            return image
        }
    }
    
    static func convert(url: URL?, image: UIImage) -> UIImage? {
        if let url,
           let cached = cache.object(forKey: url as NSURL) {
            return cached
        }
        guard let cgImage = image.cgImage else {
            return nil
        }
        return doConvert(CIImage(cgImage: cgImage), url: url)
    }
    
    static func convert(url: URL?, data: Data) -> UIImage? {
        if let url = url,
           let cached = cache.object(forKey: url as NSURL) {
            return cached
        }
        
        guard let source = CIImage(data: data) else {
            return nil
        }
        return doConvert(source, url: url)
    }
    
    static func convert(url: URL?, cgImage: CGImage) -> UIImage? {
        if let url = url,
           let cached = cache.object(forKey: url as NSURL) {
            return cached
        }
        
        return doConvert(CIImage(cgImage: cgImage), url: url)
    }
    
    private static func doConvert(_ source: CIImage, url: URL?) -> UIImage? {
        guard let filter = CIFilter(name: "CIColorMonochrome") else {
            return nil
        }
        
        filter.setValue(source, forKey: "inputImage")
        filter.setValue(CIColor(red: 0.85, green: 0.85, blue: 0.85), forKey: "inputColor")
        filter.setValue(1.0, forKey: "inputIntensity")
        
        guard let output = filter.outputImage,
              let cgImage = context.createCGImage(output, from: output.extent) else {
            return nil
        }
        let image = UIImage(cgImage: cgImage)
        
        if let url = url {
            cache.setObject(image, forKey: url as NSURL)
        }
        
        return image
    }
}
