//
//  PhotoFilterEngine.swift
//  WoWonder
//
//  Created by iMac on 27/05/25.
//  Copyright © 2025 ScriptSun. All rights reserved.
//

import Foundation
import UIKit

enum PhotoFilter: String, CaseIterable {
    case none
    case autoFix
    case brightness
    case contrast
    case documentary
    case dueTone
    case fillLight
    case fishEye
    case grain
    case grayScale
    case lomish
    case negative
    case posterize
    case saturate
    case sepia
    case sharpen
    case temperature
    case tint
    case vignette
    case crossProcess
    case blackWhite
    case flipHorizontal
    case flipVertical

    var filterName: String {
        switch self {
        case .none:
            return "None"
        case .autoFix:
            return "CIAutoAdjust"
        case .brightness:
            return "CIColorControls"
        case .contrast:
            return "CIColorControls"
        case .documentary:
            return "CIPhotoEffectProcess"
        case .dueTone:
            return "CIDuotone"
        case .fillLight:
            return "CIHighlightShadowAdjust"
        case .fishEye:
            return "CIBumpDistortion"
        case .grain:
            return "CINoiseReduction"
        case .grayScale:
            return "CIPhotoEffectMono"
        case .lomish:
            return "CIPhotoEffectTransfer"
        case .negative:
            return "CIColorInvert"
        case .posterize:
            return "CIColorPosterize"
        case .saturate:
            return "CIColorControls"
        case .sepia:
            return "CISepiaTone"
        case .sharpen:
            return "CISharpenLuminance"
        case .temperature:
            return "CITemperatureAndTint"
        case .tint:
            return "CIPhotoEffectTonal"
        case .vignette:
            return "CIVignette"
        case .crossProcess:
            return "CIPhotoEffectProcess"
        case .blackWhite:
            return "CIColorMonochrome"
        case .flipHorizontal:
            return "FlipHorizontal"
        case .flipVertical:
            return "FlipVertical"
        }
    }

    var displayName: String {
        switch self {
        case .none:
            return "Original"
        case .autoFix:
            return "AUTO FIX"
        case .brightness:
            return "BRIGHTNESS"
        case .contrast:
            return "CONTRAST"
        case .documentary:
            return "DOCUMENTARY"
        case .dueTone:
            return "DUE TONE"
        case .fillLight:
            return "FILL LIGHT"
        case .fishEye:
            return "FISH EYE"
        case .grain:
            return "GRAIN"
        case .grayScale:
            return "GRAY SCALE"
        case .lomish:
            return "LOMISH"
        case .negative:
            return "NEGATIVE"
        case .posterize:
            return "POSTERIZE"
        case .saturate:
            return "SATURATE"
        case .sepia:
            return "SEPIA"
        case .sharpen:
            return "SHARPEN"
        case .temperature:
            return "TEMPERATURE"
        case .tint:
            return "TINT"
        case .vignette:
            return "VIGNETTE"
        case .crossProcess:
            return "CROSS PROCESS"
        case .blackWhite:
            return "BLACK WHITE"
        case .flipHorizontal:
            return "FLIP HORIZONTAL"
        case .flipVertical:
            return "FLIP VERTICAL"
        }
    }
}

class PhotoFilterEngine {
    
    private let context = CIContext()
    
    func apply(filter: PhotoFilter, to image: UIImage) -> UIImage {
        guard let ciImage = CIImage(image: image) else { return image }
        let filterName: String?
        var parameters: [String: Any] = [kCIInputImageKey: ciImage]
        
        switch filter {
        case .none:
            return image
        case .autoFix:
            filterName = "CIAutoAdjust"
        case .brightness:
            filterName = "CIColorControls"
            parameters["inputBrightness"] = 0.2
        case .blackWhite:
            filterName = "CIColorMonochrome"
            parameters["inputIntensity"] = 1.0
            parameters["inputColor"] = CIColor.white
        case .contrast:
            filterName = "CIColorControls"
            parameters["inputContrast"] = 1.4
        case .crossProcess:
            filterName = "CIPhotoEffectProcess"
        case .documentary:
            filterName = "CIPhotoEffectNoir"
        case .dueTone:
            //filterName = "CISepiaTone"
            //parameters["inputIntensity"] = 0.8
            return applyDuotone(to: image, firstColor: .yellow, secondColor: .darkGray)
        case .fillLight:
            filterName = "CIHighlightShadowAdjust"
            parameters["inputShadowAmount"] = 1.0
        case .fishEye:
            filterName = "CIBumpDistortion"
            parameters["inputRadius"] = 300
            parameters["inputScale"] = 0.5
            parameters["inputCenter"] = CIVector(x: ciImage.extent.midX, y: ciImage.extent.midY)
        case .flipHorizontal:
            return image.withHorizontallyFlippedOrientation()
        case .flipVertical:
            return UIImage(cgImage: image.cgImage!, scale: image.scale, orientation: .downMirrored)
        case .grain:
            filterName = "CINoiseReduction"
            parameters["inputNoiseLevel"] = 0.02
        case .grayScale:
            filterName = "CIPhotoEffectMono"
        case .lomish:
            filterName = "CIPhotoEffectTransfer"
        case .negative:
            filterName = "CIColorInvert"
        case .posterize:
            filterName = "CIColorPosterize"
        case .saturate:
            filterName = "CIColorControls"
            parameters["inputSaturation"] = 0.5
        case .sepia:
            filterName = "CISepiaTone"
            parameters["inputIntensity"] = 1.0
        case .sharpen:
            filterName = "CISharpenLuminance"
            parameters["inputSharpness"] = 1.0
        case .temperature:
            filterName = "CITemperatureAndTint"
            parameters["inputNeutral"] = CIVector(x: 6500, y: 0)
        case .tint:
            filterName = "CIColorMonochrome"
            parameters["inputColor"] = CIColor(red: 1, green: 0, blue: 1)
        case .vignette:
            filterName = "CIVignette"
            parameters["inputIntensity"] = 0.8
            parameters["inputRadius"] = 1.0
        }
        
        guard let name = filterName, let ciFilter = CIFilter(name: name, parameters: parameters) else {
            return image
        }
        guard let outputImage = ciFilter.outputImage,
              let cgImage = context.createCGImage(outputImage, from: outputImage.extent)
        else {
            return image
        }
        
        return UIImage(cgImage: cgImage)
    }
}


private extension PhotoFilterEngine {
    
    func applyDuotone(to image: UIImage, firstColor: UIColor, secondColor: UIColor) -> UIImage {
        guard let ciImage = CIImage(image: image) else { return image }
        
        // First convert to grayscale
        guard let grayscaleFilter = CIFilter(name: "CIPhotoEffectMono") else { return image }
        grayscaleFilter.setValue(ciImage, forKey: kCIInputImageKey)
        guard let grayscaleImage = grayscaleFilter.outputImage else { return image }
        
        // Apply firstColor tint with CIColorMonochrome
        guard let monochromeFilter = CIFilter(name: "CIColorMonochrome") else { return image }
        monochromeFilter.setValue(grayscaleImage, forKey: kCIInputImageKey)
        monochromeFilter.setValue(CIColor(color: firstColor), forKey: kCIInputColorKey)
        monochromeFilter.setValue(1.0, forKey: kCIInputIntensityKey)
        guard let coloredImage = monochromeFilter.outputImage else { return image }
        
        // Create a gradient image with secondColor to overlay
        let gradient = CIFilter(name: "CILinearGradient",
                                parameters: [
                                    "inputPoint0": CIVector(x: 0, y: 0),
                                    "inputPoint1": CIVector(x: ciImage.extent.width, y: ciImage.extent.height),
                                    "inputColor0": CIColor(color: secondColor),
                                    "inputColor1": CIColor(color: .clear)
                                ])?.outputImage?.cropped(to: ciImage.extent)
        
        // Composite colored image over gradient
        guard let gradientImage = gradient else { return UIImage(ciImage: coloredImage) }
        let combined = coloredImage.composited(over: gradientImage)
        
        guard let cgImage = context.createCGImage(combined, from: ciImage.extent) else {
            return image
        }
        
        return UIImage(cgImage: cgImage, scale: image.scale, orientation: image.imageOrientation)
    }
}
