#!/usr/bin/env swift
//
// square_logo.swift
// IceGlass
//
// Usage: square_logo.swift <input.png> <output.png> <target-side-pixels>
//
// Loads an RGBA PNG, trims transparent margins (alpha bounding box),
// fits the trimmed content into a target-side × target-side transparent
// sRGB square canvas (aspect-preserved, centered), and writes PNG.
//
// The trim step matters because NHL SVG logos often ship with significant
// transparent padding inside the viewBox — without trimming, the visible
// logo only occupies a fraction of the thumbnail.
//

import CoreGraphics
import Foundation
import ImageIO
import UniformTypeIdentifiers

guard CommandLine.arguments.count == 4,
      let targetSize = Int(CommandLine.arguments[3]),
      targetSize > 0
else {
    FileHandle.standardError.write(
        Data("Usage: square_logo.swift <input.png> <output.png> <target-side-pixels>\n".utf8)
    )
    exit(2)
}

let inputURL = URL(fileURLWithPath: CommandLine.arguments[1])
let outputURL = URL(fileURLWithPath: CommandLine.arguments[2])

guard let source = CGImageSourceCreateWithURL(inputURL as CFURL, nil),
      let srcImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
    FileHandle.standardError.write(Data("failed to load \(inputURL.path)\n".utf8))
    exit(1)
}

// MARK: - Find alpha bounding box

/// Read the source image into a premultiplied RGBA8 buffer so we can scan
/// pixels directly, then find the tightest rectangle enclosing all alpha
/// values above a small threshold.
func alphaBoundingBox(_ image: CGImage, alphaThreshold: UInt8 = 8) -> CGRect? {
    let w = image.width
    let h = image.height
    let bytesPerPixel = 4
    let bytesPerRow = w * bytesPerPixel
    var buffer = [UInt8](repeating: 0, count: h * bytesPerRow)

    let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) ?? CGColorSpaceCreateDeviceRGB()
    guard let ctx = CGContext(
        data: &buffer, width: w, height: h,
        bitsPerComponent: 8, bytesPerRow: bytesPerRow,
        space: colorSpace,
        bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
    ) else { return nil }
    ctx.draw(image, in: CGRect(x: 0, y: 0, width: w, height: h))

    var minX = w, minY = h, maxX = -1, maxY = -1
    for y in 0..<h {
        for x in 0..<w {
            let alpha = buffer[y * bytesPerRow + x * bytesPerPixel + 3]
            if alpha > alphaThreshold {
                if x < minX { minX = x }
                if x > maxX { maxX = x }
                if y < minY { minY = y }
                if y > maxY { maxY = y }
            }
        }
    }
    guard maxX >= minX, maxY >= minY else { return nil }
    return CGRect(x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1)
}

let bbox = alphaBoundingBox(srcImage) ?? CGRect(x: 0, y: 0, width: srcImage.width, height: srcImage.height)

// MARK: - Crop to bbox, then fit into target square

guard let cropped = srcImage.cropping(to: bbox) else {
    FileHandle.standardError.write(Data("crop failed\n".utf8))
    exit(1)
}

let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) ?? CGColorSpaceCreateDeviceRGB()
guard let ctx = CGContext(
    data: nil,
    width: targetSize,
    height: targetSize,
    bitsPerComponent: 8,
    bytesPerRow: 0,
    space: colorSpace,
    bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
) else {
    FileHandle.standardError.write(Data("CGContext create failed\n".utf8))
    exit(1)
}
ctx.interpolationQuality = .high
ctx.clear(CGRect(x: 0, y: 0, width: targetSize, height: targetSize))

let cw = CGFloat(cropped.width)
let ch = CGFloat(cropped.height)
let S = CGFloat(targetSize)
let scale = min(S / cw, S / ch)
let dw = cw * scale
let dh = ch * scale
let drawRect = CGRect(x: (S - dw) / 2, y: (S - dh) / 2, width: dw, height: dh)
ctx.draw(cropped, in: drawRect)

guard let final = ctx.makeImage(),
      let dest = CGImageDestinationCreateWithURL(
          outputURL as CFURL, UTType.png.identifier as CFString, 1, nil
      )
else {
    FileHandle.standardError.write(Data("image/dest create failed\n".utf8))
    exit(1)
}
CGImageDestinationAddImage(dest, final, nil)
guard CGImageDestinationFinalize(dest) else {
    FileHandle.standardError.write(Data("finalize failed\n".utf8))
    exit(1)
}
