import AppKit
import Foundation

struct IconRenderer {
    let size: CGFloat

    func render(to url: URL) throws {
        guard
            let bitmap = NSBitmapImageRep(
                bitmapDataPlanes: nil,
                pixelsWide: Int(size),
                pixelsHigh: Int(size),
                bitsPerSample: 8,
                samplesPerPixel: 4,
                hasAlpha: true,
                isPlanar: false,
                colorSpaceName: .deviceRGB,
                bytesPerRow: 0,
                bitsPerPixel: 0
            ),
            let graphics = NSGraphicsContext(bitmapImageRep: bitmap)
        else { return }

        NSGraphicsContext.saveGraphicsState()
        NSGraphicsContext.current = graphics
        defer { NSGraphicsContext.restoreGraphicsState() }

        let context = graphics.cgContext
        context.setShouldAntialias(true)
        context.setAllowsAntialiasing(true)

        let rect = CGRect(x: 0, y: 0, width: size, height: size)
        let scale = size / 1024
        let radius = 226 * scale
        let base = CGPath(
            roundedRect: rect.insetBy(dx: 44 * scale, dy: 44 * scale),
            cornerWidth: radius,
            cornerHeight: radius,
            transform: nil
        )

        context.addPath(base)
        context.clip()

        let background = CGGradient(
            colorsSpace: CGColorSpaceCreateDeviceRGB(),
            colors: [
                NSColor(calibratedRed: 0.04, green: 0.12, blue: 0.24, alpha: 1).cgColor,
                NSColor(calibratedRed: 0.12, green: 0.20, blue: 0.42, alpha: 1).cgColor,
                NSColor(calibratedRed: 0.58, green: 0.16, blue: 0.88, alpha: 1).cgColor
            ] as CFArray,
            locations: [0, 0.52, 1]
        )!
        context.drawLinearGradient(
            background,
            start: CGPoint(x: rect.minX, y: rect.maxY),
            end: CGPoint(x: rect.maxX, y: rect.minY),
            options: []
        )

        drawGlow(context, color: NSColor.systemBlue, center: CGPoint(x: 260 * scale, y: 760 * scale), radius: 330 * scale)
        drawGlow(context, color: NSColor.systemPurple, center: CGPoint(x: 785 * scale, y: 285 * scale), radius: 430 * scale)
        drawGlassHighlight(context, rect: rect, scale: scale)
        drawBars(context, scale: scale)
        drawLens(context, scale: scale)

        context.resetClip()
        context.addPath(base)
        context.setStrokeColor(NSColor.white.withAlphaComponent(0.22).cgColor)
        context.setLineWidth(12 * scale)
        context.strokePath()

        guard let png = bitmap.representation(using: .png, properties: [:]) else { return }
        try png.write(to: url)
    }

    private func drawGlow(_ context: CGContext, color: NSColor, center: CGPoint, radius: CGFloat) {
        let gradient = CGGradient(
            colorsSpace: CGColorSpaceCreateDeviceRGB(),
            colors: [
                color.withAlphaComponent(0.55).cgColor,
                color.withAlphaComponent(0.0).cgColor
            ] as CFArray,
            locations: [0, 1]
        )!
        context.drawRadialGradient(
            gradient,
            startCenter: center,
            startRadius: 0,
            endCenter: center,
            endRadius: radius,
            options: []
        )
    }

    private func drawGlassHighlight(_ context: CGContext, rect: CGRect, scale: CGFloat) {
        let highlight = CGGradient(
            colorsSpace: CGColorSpaceCreateDeviceRGB(),
            colors: [
                NSColor.white.withAlphaComponent(0.32).cgColor,
                NSColor.white.withAlphaComponent(0.06).cgColor,
                NSColor.white.withAlphaComponent(0.0).cgColor
            ] as CFArray,
            locations: [0, 0.36, 1]
        )!
        let path = CGPath(
            roundedRect: CGRect(x: 120 * scale, y: 610 * scale, width: 790 * scale, height: 268 * scale),
            cornerWidth: 130 * scale,
            cornerHeight: 130 * scale,
            transform: nil
        )
        context.saveGState()
        context.addPath(path)
        context.clip()
        context.drawLinearGradient(
            highlight,
            start: CGPoint(x: rect.minX, y: rect.maxY),
            end: CGPoint(x: rect.maxX, y: rect.minY),
            options: []
        )
        context.restoreGState()
    }

    private func drawBars(_ context: CGContext, scale: CGFloat) {
        let bars = [
            CGRect(x: 288, y: 286, width: 86, height: 300),
            CGRect(x: 430, y: 212, width: 86, height: 448),
            CGRect(x: 572, y: 330, width: 86, height: 252)
        ].map { CGRect(x: $0.minX * scale, y: $0.minY * scale, width: $0.width * scale, height: $0.height * scale) }

        for (index, bar) in bars.enumerated() {
            let color: NSColor = index == 1 ? .white : NSColor(calibratedWhite: 1, alpha: 0.88)
            let path = CGPath(
                roundedRect: bar,
                cornerWidth: 44 * scale,
                cornerHeight: 44 * scale,
                transform: nil
            )
            context.addPath(path)
            context.setFillColor(color.cgColor)
            context.fillPath()
        }
    }

    private func drawLens(_ context: CGContext, scale: CGFloat) {
        let ring = CGRect(x: 682 * scale, y: 228 * scale, width: 170 * scale, height: 170 * scale)
        context.setStrokeColor(NSColor.white.withAlphaComponent(0.92).cgColor)
        context.setLineWidth(34 * scale)
        context.strokeEllipse(in: ring)
        context.setLineCap(.round)
        context.move(to: CGPoint(x: 805 * scale, y: 275 * scale))
        context.addLine(to: CGPoint(x: 892 * scale, y: 188 * scale))
        context.strokePath()
    }
}

let outputRoot = URL(fileURLWithPath: CommandLine.arguments.dropFirst().first ?? "NativeTokenLens/Assets/AppIcon.iconset")
try FileManager.default.createDirectory(at: outputRoot, withIntermediateDirectories: true)

let specs: [(String, CGFloat)] = [
    ("icon_16x16.png", 16),
    ("icon_16x16@2x.png", 32),
    ("icon_32x32.png", 32),
    ("icon_32x32@2x.png", 64),
    ("icon_128x128.png", 128),
    ("icon_128x128@2x.png", 256),
    ("icon_256x256.png", 256),
    ("icon_256x256@2x.png", 512),
    ("icon_512x512.png", 512),
    ("icon_512x512@2x.png", 1024)
]

for spec in specs {
    try IconRenderer(size: spec.1).render(to: outputRoot.appendingPathComponent(spec.0))
}
