import CoreGraphics
import Foundation
import ImageIO

func clamp(_ value: Int, min minValue: Int, max maxValue: Int) -> Int {
    Swift.max(minValue, Swift.min(maxValue, value))
}

func resizedImage(_ image: CGImage, targetWidth: Int) -> CGImage? {
    if targetWidth <= 0 || targetWidth >= image.width {
        return image
    }
    let targetHeight = Swift.max(1, Int(Double(image.height) * Double(targetWidth) / Double(image.width)))
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    guard let context = CGContext(
        data: nil,
        width: targetWidth,
        height: targetHeight,
        bitsPerComponent: 8,
        bytesPerRow: 0,
        space: colorSpace,
        bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
    ) else {
        return nil
    }
    context.interpolationQuality = .medium
    context.draw(image, in: CGRect(x: 0, y: 0, width: targetWidth, height: targetHeight))
    return context.makeImage()
}

func encodeJpeg(_ image: CGImage, quality: Int) -> Data? {
    let data = NSMutableData()
    guard let destination = CGImageDestinationCreateWithData(
        data,
        "public.jpeg" as CFString,
        1,
        nil
    ) else {
        return nil
    }
    let options = [
        kCGImageDestinationLossyCompressionQuality: Double(clamp(quality, min: 1, max: 100)) / 100.0,
        kCGImagePropertyJFIFDictionary: [
            kCGImagePropertyJFIFIsProgressive: false
        ]
    ] as CFDictionary
    CGImageDestinationAddImage(destination, image, options)
    guard CGImageDestinationFinalize(destination) else { return nil }
    return data as Data
}

let args = CommandLine.arguments
let inputPath = args.dropFirst().first ?? ""
let width = clamp(Int(args.dropFirst(2).first ?? "") ?? 960, min: 480, max: 1920)
let quality = clamp(Int(args.dropFirst(3).first ?? "") ?? 62, min: 25, max: 90)

guard !inputPath.isEmpty else {
    FileHandle.standardError.write(Data("Input path is required.\n".utf8))
    exit(2)
}

let inputUrl = URL(fileURLWithPath: inputPath)
guard let source = CGImageSourceCreateWithURL(inputUrl as CFURL, nil),
      let image = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
    FileHandle.standardError.write(Data("Unable to read input image.\n".utf8))
    exit(2)
}

guard let scaled = resizedImage(image, targetWidth: width),
      let jpeg = encodeJpeg(scaled, quality: quality) else {
    FileHandle.standardError.write(Data("Unable to encode JPEG.\n".utf8))
    exit(3)
}

FileHandle.standardOutput.write(jpeg)
