import AppKit
import Foundation

let canvasSize = CGSize(width: 1024, height: 1024)

enum Palette {
    static let accent = NSColor(hex: 0x6366F1)
    static let accentLight = NSColor(hex: 0x818CF8)
    static let boarding = NSColor(hex: 0x3B82F6)
    static let mint = NSColor(hex: 0x10B981)
    static let slate = NSColor(hex: 0x0F172A)
    static let sky = NSColor(hex: 0x38BDF8)
    static let cloud = NSColor(hex: 0xE2E8F0)
    static let mist = NSColor(hex: 0xF8FAFC)
    static let ink = NSColor(hex: 0x111827)
}

struct IconOption {
    let fileName: String
    let label: String
    let draw: (CGRect) -> Void
}

extension NSColor {
    convenience init(hex: UInt32, alpha: CGFloat = 1.0) {
        self.init(
            calibratedRed: CGFloat((hex >> 16) & 0xFF) / 255.0,
            green: CGFloat((hex >> 8) & 0xFF) / 255.0,
            blue: CGFloat(hex & 0xFF) / 255.0,
            alpha: alpha
        )
    }
}

extension CGRect {
    var center: CGPoint { CGPoint(x: midX, y: midY) }
}

func roundedRectPath(_ rect: CGRect, radius: CGFloat) -> NSBezierPath {
    NSBezierPath(roundedRect: rect, xRadius: radius, yRadius: radius)
}

func circleRect(center: CGPoint, radius: CGFloat) -> CGRect {
    CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)
}

func withGraphicsState(_ draw: () -> Void) {
    NSGraphicsContext.saveGraphicsState()
    draw()
    NSGraphicsContext.restoreGraphicsState()
}

func applyShadow(
    color: NSColor,
    blur: CGFloat,
    x: CGFloat = 0,
    y: CGFloat = 0,
    draw: () -> Void
) {
    withGraphicsState {
        let shadow = NSShadow()
        shadow.shadowColor = color
        shadow.shadowBlurRadius = blur
        shadow.shadowOffset = NSSize(width: x, height: y)
        shadow.set()
        draw()
    }
}

func fillPath(_ path: NSBezierPath, colors: [NSColor], angle: CGFloat) {
    guard let gradient = NSGradient(colors: colors) else { return }
    gradient.draw(in: path, angle: angle)
}

func strokePath(_ path: NSBezierPath, color: NSColor, lineWidth: CGFloat) {
    color.setStroke()
    path.lineWidth = lineWidth
    path.stroke()
}

func fillCircle(center: CGPoint, radius: CGFloat, color: NSColor) {
    let path = NSBezierPath(ovalIn: circleRect(center: center, radius: radius))
    color.setFill()
    path.fill()
}

func fillRoundedRect(_ rect: CGRect, radius: CGFloat, colors: [NSColor], angle: CGFloat) {
    let path = roundedRectPath(rect, radius: radius)
    fillPath(path, colors: colors, angle: angle)
}

func drawSymbol(
    _ name: String,
    in rect: CGRect,
    pointSize: CGFloat,
    tint: NSColor,
    weight: NSFont.Weight = .regular,
    scale: NSImage.SymbolScale = .large,
    rotationDegrees: CGFloat = 0,
    alpha: CGFloat = 1.0
) {
    guard
        let symbol = NSImage(systemSymbolName: name, accessibilityDescription: nil),
        let configured = symbol.withSymbolConfiguration(.init(pointSize: pointSize, weight: weight, scale: scale))
    else {
        return
    }

    let tinted = NSImage(size: configured.size)
    tinted.lockFocus()
    let imageRect = NSRect(origin: .zero, size: configured.size)
    configured.draw(in: imageRect, from: NSRect.zero, operation: NSCompositingOperation.sourceOver, fraction: 1.0)
    tint.withAlphaComponent(alpha).set()
    imageRect.fill(using: NSCompositingOperation.sourceAtop)
    tinted.unlockFocus()

    withGraphicsState {
        let transform = NSAffineTransform()
        transform.translateX(by: rect.midX, yBy: rect.midY)
        transform.rotate(byDegrees: rotationDegrees)
        transform.translateX(by: -rect.midX, yBy: -rect.midY)
        transform.concat()
        tinted.draw(in: rect, from: NSRect.zero, operation: NSCompositingOperation.sourceOver, fraction: 1.0)
    }
}

func quadraticPath(start: CGPoint, control: CGPoint, end: CGPoint) -> NSBezierPath {
    let cp1 = CGPoint(
        x: start.x + ((control.x - start.x) * 2.0 / 3.0),
        y: start.y + ((control.y - start.y) * 2.0 / 3.0)
    )
    let cp2 = CGPoint(
        x: end.x + ((control.x - end.x) * 2.0 / 3.0),
        y: end.y + ((control.y - end.y) * 2.0 / 3.0)
    )
    let path = NSBezierPath()
    path.move(to: start)
    path.curve(to: end, controlPoint1: cp1, controlPoint2: cp2)
    return path
}

func quadraticPoint(start: CGPoint, control: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint {
    let oneMinusT = 1 - t
    let x = (oneMinusT * oneMinusT * start.x) + (2 * oneMinusT * t * control.x) + (t * t * end.x)
    let y = (oneMinusT * oneMinusT * start.y) + (2 * oneMinusT * t * control.y) + (t * t * end.y)
    return CGPoint(x: x, y: y)
}

func quadraticAngle(start: CGPoint, control: CGPoint, end: CGPoint, t: CGFloat) -> CGFloat {
    let dx = (2 * (1 - t) * (control.x - start.x)) + (2 * t * (end.x - control.x))
    let dy = (2 * (1 - t) * (control.y - start.y)) + (2 * t * (end.y - control.y))
    return atan2(dy, dx) * 180 / .pi
}

func drawRouteArc(
    start: CGPoint,
    control: CGPoint,
    end: CGPoint,
    color: NSColor,
    lineWidth: CGFloat,
    dash: [CGFloat] = [22, 18]
) {
    let path = quadraticPath(start: start, control: control, end: end)
    color.setStroke()
    path.lineWidth = lineWidth
    path.lineCapStyle = .round
    path.setLineDash(dash, count: dash.count, phase: 0)
    path.stroke()
}

func drawRing(center: CGPoint, radius: CGFloat, width: CGFloat, color: NSColor, alpha: CGFloat = 1.0) {
    let path = NSBezierPath(ovalIn: circleRect(center: center, radius: radius))
    strokePath(path, color: color.withAlphaComponent(alpha), lineWidth: width)
}

func drawGlobe(
    center: CGPoint,
    radius: CGFloat,
    fillColors: [NSColor],
    landTint: NSColor,
    gridColor: NSColor,
    highlightColor: NSColor,
    landAlpha: CGFloat = 0.35,
    strokeColor: NSColor? = nil,
    glowColor: NSColor? = nil
) {
    let globeRect = circleRect(center: center, radius: radius)
    let globePath = NSBezierPath(ovalIn: globeRect)

    if let glowColor {
        applyShadow(color: glowColor, blur: 48) {
            fillCircle(center: center, radius: radius * 0.96, color: glowColor.withAlphaComponent(0.35))
        }
    }

    fillPath(globePath, colors: fillColors, angle: 90)

    withGraphicsState {
        globePath.addClip()

        let continentsRect = globeRect.insetBy(dx: radius * 0.12, dy: radius * 0.12)
        drawSymbol(
            "globe.americas.fill",
            in: continentsRect.offsetBy(dx: radius * 0.03, dy: radius * -0.02),
            pointSize: radius * 1.3,
            tint: landTint,
            weight: .regular,
            rotationDegrees: 0,
            alpha: landAlpha
        )

        let meridians: [CGFloat] = [0.42, 0.72]
        for scale in meridians {
            let ellipse = NSBezierPath(
                ovalIn: CGRect(
                    x: center.x - radius * scale,
                    y: center.y - radius,
                    width: radius * scale * 2,
                    height: radius * 2
                )
            )
            strokePath(ellipse, color: gridColor.withAlphaComponent(0.9), lineWidth: 5)
        }

        let parallels: [CGFloat] = [0.30, 0.62, 0.86]
        for scale in parallels {
            let ellipse = NSBezierPath(
                ovalIn: CGRect(
                    x: center.x - radius,
                    y: center.y - radius * scale,
                    width: radius * 2,
                    height: radius * scale * 2
                )
            )
            strokePath(ellipse, color: gridColor.withAlphaComponent(0.68), lineWidth: 4)
        }

        let specular = NSBezierPath(
            ovalIn: CGRect(
                x: center.x - radius * 0.62,
                y: center.y + radius * 0.16,
                width: radius * 0.70,
                height: radius * 0.36
            )
        )
        highlightColor.withAlphaComponent(0.18).setFill()
        specular.fill()
    }

    if let strokeColor {
        strokePath(globePath, color: strokeColor, lineWidth: 6)
    }
}

func drawTopographicLines(rect: CGRect, color: NSColor, count: Int, inset: CGFloat) {
    for index in 0..<count {
        let y = rect.minY + inset + (CGFloat(index) * ((rect.height - inset * 2) / CGFloat(count)))
        let path = NSBezierPath()
        path.move(to: CGPoint(x: rect.minX + inset, y: y))
        path.curve(
            to: CGPoint(x: rect.maxX - inset, y: y + 24),
            controlPoint1: CGPoint(x: rect.minX + rect.width * 0.28, y: y - 38),
            controlPoint2: CGPoint(x: rect.minX + rect.width * 0.68, y: y + 64)
        )
        path.lineWidth = 3
        path.setLineDash([18, 14], count: 2, phase: CGFloat(index) * 6)
        color.setStroke()
        path.stroke()
    }
}

func drawStarField(rect: CGRect, stars: [(CGFloat, CGFloat, CGFloat, CGFloat)]) {
    for (x, y, size, alpha) in stars {
        fillCircle(
            center: CGPoint(x: rect.minX + x * rect.width, y: rect.minY + y * rect.height),
            radius: size,
            color: NSColor.white.withAlphaComponent(alpha)
        )
    }
}

func drawOrbitalRoute(rect: CGRect) {
    fillRoundedRect(
        rect,
        radius: 220,
        colors: [
            NSColor(hex: 0x08111F),
            NSColor(hex: 0x1D2A64),
            NSColor(hex: 0x4F46E5)
        ],
        angle: 42
    )

    fillCircle(center: CGPoint(x: 214, y: 860), radius: 170, color: Palette.accentLight.withAlphaComponent(0.14))
    fillCircle(center: CGPoint(x: 832, y: 248), radius: 200, color: Palette.sky.withAlphaComponent(0.18))

    drawGlobe(
        center: CGPoint(x: 332, y: 368),
        radius: 302,
        fillColors: [NSColor(hex: 0x183B6C), NSColor(hex: 0x0C1834)],
        landTint: NSColor.white,
        gridColor: NSColor.white.withAlphaComponent(0.34),
        highlightColor: NSColor.white,
        landAlpha: 0.18,
        strokeColor: NSColor.white.withAlphaComponent(0.12),
        glowColor: Palette.sky.withAlphaComponent(0.2)
    )

    let start = CGPoint(x: 272, y: 464)
    let control = CGPoint(x: 500, y: 940)
    let end = CGPoint(x: 830, y: 744)
    drawRouteArc(
        start: start,
        control: control,
        end: end,
        color: NSColor.white.withAlphaComponent(0.50),
        lineWidth: 16
    )

    fillCircle(center: start, radius: 22, color: Palette.mint)
    applyShadow(color: NSColor.black.withAlphaComponent(0.28), blur: 24, y: -8) {
        let planeCenter = quadraticPoint(start: start, control: control, end: end, t: 0.58)
        let planeAngle = quadraticAngle(start: start, control: control, end: end, t: 0.58) - 6
        drawSymbol(
            "airplane",
            in: CGRect(x: planeCenter.x - 92, y: planeCenter.y - 64, width: 184, height: 128),
            pointSize: 150,
            tint: NSColor.white,
            weight: .semibold,
            rotationDegrees: planeAngle
        )
    }
}

func drawWindowBadge(rect: CGRect) {
    fillRoundedRect(
        rect,
        radius: 220,
        colors: [
            NSColor(hex: 0xE0F2FE),
            NSColor(hex: 0xC7D2FE),
            NSColor(hex: 0x93C5FD)
        ],
        angle: 65
    )

    drawRing(center: CGPoint(x: 300, y: 832), radius: 116, width: 30, color: NSColor.white, alpha: 0.20)
    fillCircle(center: CGPoint(x: 796, y: 226), radius: 180, color: Palette.accent.withAlphaComponent(0.12))

    let badgeCenter = CGPoint(x: 512, y: 528)
    let badgeRadius: CGFloat = 356
    applyShadow(color: NSColor.black.withAlphaComponent(0.18), blur: 38, y: -14) {
        drawGlobe(
            center: badgeCenter,
            radius: badgeRadius,
            fillColors: [NSColor(hex: 0x5046E5), NSColor(hex: 0x1E1B4B)],
            landTint: NSColor.white,
            gridColor: NSColor.white.withAlphaComponent(0.55),
            highlightColor: NSColor.white,
            landAlpha: 0.15,
            strokeColor: NSColor.white.withAlphaComponent(0.14),
            glowColor: Palette.accent.withAlphaComponent(0.2)
        )
    }

    fillCircle(center: CGPoint(x: 406, y: 662), radius: 104, color: NSColor.white.withAlphaComponent(0.10))

    let orbit = NSBezierPath(ovalIn: circleRect(center: badgeCenter, radius: badgeRadius + 58))
    orbit.lineWidth = 22
    orbit.setLineDash([170, 44], count: 2, phase: 82)
    NSColor.white.withAlphaComponent(0.58).setStroke()
    orbit.stroke()

    let planeRect = CGRect(x: 674, y: 680, width: 220, height: 160)
    applyShadow(color: NSColor.black.withAlphaComponent(0.28), blur: 24, y: -10) {
        drawSymbol(
            "airplane",
            in: planeRect,
            pointSize: 170,
            tint: NSColor.white,
            weight: .semibold,
            rotationDegrees: 32
        )
    }
}

func drawAtlasTile(rect: CGRect) {
    fillRoundedRect(
        rect,
        radius: 220,
        colors: [
            NSColor(hex: 0xF8FAFC),
            NSColor(hex: 0xEEF2FF),
            NSColor(hex: 0xDBEAFE)
        ],
        angle: 90
    )

    drawTopographicLines(rect: rect, color: Palette.accent.withAlphaComponent(0.14), count: 10, inset: 84)

    let roundelRect = CGRect(x: 176, y: 176, width: 672, height: 672)
    let roundelPath = NSBezierPath(roundedRect: roundelRect, xRadius: 190, yRadius: 190)
    applyShadow(color: NSColor.black.withAlphaComponent(0.12), blur: 24, y: -10) {
        fillPath(
            roundelPath,
            colors: [
                NSColor(hex: 0x0F172A),
                NSColor(hex: 0x1E293B),
                NSColor(hex: 0x312E81)
            ],
            angle: 50
        )
    }

    drawGlobe(
        center: CGPoint(x: 512, y: 512),
        radius: 244,
        fillColors: [NSColor(hex: 0x1D4ED8), NSColor(hex: 0x1E3A8A)],
        landTint: NSColor.white,
        gridColor: NSColor.white.withAlphaComponent(0.55),
        highlightColor: NSColor.white,
        landAlpha: 0.20,
        strokeColor: NSColor.white.withAlphaComponent(0.10),
        glowColor: Palette.boarding.withAlphaComponent(0.10)
    )

    let orbit = NSBezierPath()
    orbit.move(to: CGPoint(x: 228, y: 384))
    orbit.curve(
        to: CGPoint(x: 786, y: 670),
        controlPoint1: CGPoint(x: 322, y: 804),
        controlPoint2: CGPoint(x: 650, y: 870)
    )
    orbit.lineWidth = 18
    orbit.lineCapStyle = .round
    orbit.setLineDash([28, 22], count: 2, phase: 0)
    Palette.accentLight.withAlphaComponent(0.82).setStroke()
    orbit.stroke()

    fillCircle(center: CGPoint(x: 786, y: 670), radius: 18, color: Palette.mint)

    applyShadow(color: NSColor.black.withAlphaComponent(0.28), blur: 24, y: -6) {
        drawSymbol(
            "airplane",
            in: CGRect(x: 356, y: 408, width: 320, height: 230),
            pointSize: 246,
            tint: NSColor.white,
            weight: .bold,
            rotationDegrees: 28
        )
    }
}

func drawNightRing(rect: CGRect) {
    fillRoundedRect(
        rect,
        radius: 220,
        colors: [
            NSColor(hex: 0x020617),
            NSColor(hex: 0x111827),
            NSColor(hex: 0x172554)
        ],
        angle: 50
    )

    drawStarField(
        rect: rect,
        stars: [
            (0.18, 0.82, 5, 0.70),
            (0.29, 0.74, 3, 0.42),
            (0.77, 0.81, 4, 0.58),
            (0.67, 0.69, 3, 0.36),
            (0.86, 0.34, 5, 0.62),
            (0.15, 0.30, 4, 0.44)
        ]
    )

    let center = CGPoint(x: 512, y: 512)
    fillCircle(center: center, radius: 350, color: Palette.sky.withAlphaComponent(0.07))

    drawRing(center: center, radius: 338, width: 28, color: Palette.sky, alpha: 0.92)
    drawRing(center: center, radius: 378, width: 6, color: NSColor.white, alpha: 0.20)

    drawGlobe(
        center: center,
        radius: 252,
        fillColors: [NSColor(hex: 0x0F766E), NSColor(hex: 0x0F172A)],
        landTint: NSColor.white,
        gridColor: NSColor.white.withAlphaComponent(0.44),
        highlightColor: NSColor.white,
        landAlpha: 0.16,
        strokeColor: NSColor.white.withAlphaComponent(0.10),
        glowColor: Palette.sky.withAlphaComponent(0.18)
    )

    fillCircle(center: CGPoint(x: 512, y: 512), radius: 178, color: Palette.mint.withAlphaComponent(0.10))

    applyShadow(color: NSColor.black.withAlphaComponent(0.30), blur: 20, y: -6) {
        drawSymbol(
            "airplane",
            in: CGRect(x: 668, y: 676, width: 194, height: 140),
            pointSize: 148,
            tint: NSColor.white,
            weight: .semibold,
            rotationDegrees: 36
        )
    }
}

func drawRouteCard(rect: CGRect) {
    fillRoundedRect(
        rect,
        radius: 220,
        colors: [
            NSColor(hex: 0xF8FAFC),
            NSColor(hex: 0xEEF2FF),
            NSColor(hex: 0xE0E7FF)
        ],
        angle: 70
    )

    let backCard = CGRect(x: 176, y: 204, width: 684, height: 614)
    let frontCard = CGRect(x: 132, y: 246, width: 760, height: 560)

    let backPath = roundedRectPath(backCard, radius: 88)
    let frontPath = roundedRectPath(frontCard, radius: 96)

    applyShadow(color: NSColor.black.withAlphaComponent(0.10), blur: 18, y: -8) {
        fillPath(backPath, colors: [Palette.accentLight.withAlphaComponent(0.30), Palette.boarding.withAlphaComponent(0.18)], angle: 12)
    }

    applyShadow(color: NSColor.black.withAlphaComponent(0.12), blur: 24, y: -10) {
        fillPath(frontPath, colors: [NSColor.white, NSColor(hex: 0xEEF2FF)], angle: 90)
    }
    strokePath(frontPath, color: Palette.cloud.withAlphaComponent(0.88), lineWidth: 4)

    let globeCenter = CGPoint(x: 314, y: 584)
    drawGlobe(
        center: globeCenter,
        radius: 156,
        fillColors: [Palette.accentLight, Palette.accent],
        landTint: NSColor.white,
        gridColor: NSColor.white.withAlphaComponent(0.52),
        highlightColor: NSColor.white,
        landAlpha: 0.18,
        strokeColor: NSColor.white.withAlphaComponent(0.10),
        glowColor: Palette.accent.withAlphaComponent(0.12)
    )

    let start = CGPoint(x: 346, y: 438)
    let control = CGPoint(x: 548, y: 754)
    let end = CGPoint(x: 780, y: 538)
    drawRouteArc(
        start: start,
        control: control,
        end: end,
        color: Palette.ink.withAlphaComponent(0.32),
        lineWidth: 16,
        dash: [20, 18]
    )
    fillCircle(center: start, radius: 20, color: Palette.mint)
    fillCircle(center: end, radius: 20, color: Palette.boarding)

    let planeCenter = quadraticPoint(start: start, control: control, end: end, t: 0.58)
    let planeAngle = quadraticAngle(start: start, control: control, end: end, t: 0.58) - 10
    applyShadow(color: NSColor.black.withAlphaComponent(0.18), blur: 16, y: -4) {
        drawSymbol(
            "airplane",
            in: CGRect(x: planeCenter.x - 102, y: planeCenter.y - 72, width: 204, height: 144),
            pointSize: 166,
            tint: Palette.ink,
            weight: .bold,
            rotationDegrees: planeAngle
        )
    }

    let detailPill = roundedRectPath(CGRect(x: 226, y: 318, width: 360, height: 28), radius: 14)
    fillPath(detailPill, colors: [Palette.cloud.withAlphaComponent(0.92), Palette.cloud.withAlphaComponent(0.92)], angle: 0)

    let accentPill = roundedRectPath(CGRect(x: 226, y: 272, width: 220, height: 28), radius: 14)
    fillPath(
        accentPill,
        colors: [Palette.accent.withAlphaComponent(0.16), Palette.boarding.withAlphaComponent(0.16)],
        angle: 0
    )

    let actionChip = roundedRectPath(CGRect(x: 620, y: 270, width: 164, height: 54), radius: 27)
    fillPath(actionChip, colors: [Palette.accent, Palette.boarding], angle: 0)

    drawSymbol(
        "airplane.departure",
        in: CGRect(x: 662, y: 282, width: 82, height: 34),
        pointSize: 46,
        tint: NSColor.white,
        weight: .bold
    )
}

func renderBitmap(size: CGSize = canvasSize, draw: (CGRect) -> Void) -> NSBitmapImageRep {
    let rep = NSBitmapImageRep(
        bitmapDataPlanes: nil,
        pixelsWide: Int(size.width),
        pixelsHigh: Int(size.height),
        bitsPerSample: 8,
        samplesPerPixel: 4,
        hasAlpha: true,
        isPlanar: false,
        colorSpaceName: .deviceRGB,
        bytesPerRow: 0,
        bitsPerPixel: 0
    )!

    rep.size = size

    let graphicsContext = NSGraphicsContext(bitmapImageRep: rep)!
    NSGraphicsContext.saveGraphicsState()
    NSGraphicsContext.current = graphicsContext
    draw(CGRect(origin: .zero, size: size))
    graphicsContext.flushGraphics()
    NSGraphicsContext.restoreGraphicsState()
    return rep
}

func savePNG(_ rep: NSBitmapImageRep, to url: URL) throws {
    guard let data = rep.representation(using: .png, properties: [:]) else {
        throw NSError(domain: "IconGenerator", code: 1)
    }
    try data.write(to: url)
}

func drawComparisonSheet(options: [IconOption], imageDirectory: URL, outputURL: URL) throws {
    let sheetSize = CGSize(width: 2190, height: 1620)
    let rep = renderBitmap(size: sheetSize) { rect in
        fillRoundedRect(
            rect,
            radius: 120,
            colors: [NSColor(hex: 0xF8FAFC), NSColor(hex: 0xEEF2FF)],
            angle: 90
        )

        let titleAttributes: [NSAttributedString.Key: Any] = [
            .font: NSFont.systemFont(ofSize: 82, weight: .bold),
            .foregroundColor: Palette.slate
        ]
        let subtitleAttributes: [NSAttributedString.Key: Any] = [
            .font: NSFont.systemFont(ofSize: 34, weight: .medium),
            .foregroundColor: Palette.ink.withAlphaComponent(0.70)
        ]
        NSAttributedString(string: "Flights App Icon Concepts", attributes: titleAttributes)
            .draw(at: CGPoint(x: 112, y: 1470))
        NSAttributedString(
            string: "1 to 5. Same palette, different attitude.",
            attributes: subtitleAttributes
        )
        .draw(at: CGPoint(x: 118, y: 1412))

        let cardWidth: CGFloat = 354
        let cardHeight: CGFloat = 474
        let horizontalGap: CGFloat = 52
        let verticalGap: CGFloat = 50
        let startX: CGFloat = 112
        let startY: CGFloat = 856

        for (index, option) in options.enumerated() {
            let row = index / 3
            let column = index % 3
            let x = startX + CGFloat(column) * (cardWidth + horizontalGap)
            let y = startY - CGFloat(row) * (cardHeight + verticalGap)
            let cardRect = CGRect(x: x, y: y, width: cardWidth, height: cardHeight)

            let cardPath = roundedRectPath(cardRect, radius: 52)
            applyShadow(color: NSColor.black.withAlphaComponent(0.10), blur: 20, y: -8) {
                fillPath(cardPath, colors: [NSColor.white, NSColor(hex: 0xF8FAFC)], angle: 90)
            }

            let imageURL = imageDirectory.appendingPathComponent(option.fileName)
            if let image = NSImage(contentsOf: imageURL) {
                image.draw(in: CGRect(x: x + 27, y: y + 116, width: 300, height: 300))
            }

            let labelAttributes: [NSAttributedString.Key: Any] = [
                .font: NSFont.monospacedSystemFont(ofSize: 30, weight: .bold),
                .foregroundColor: Palette.accent
            ]
            let titleAttributes: [NSAttributedString.Key: Any] = [
                .font: NSFont.systemFont(ofSize: 34, weight: .semibold),
                .foregroundColor: Palette.slate
            ]
            NSAttributedString(string: "\(index + 1).", attributes: labelAttributes)
                .draw(at: CGPoint(x: x + 28, y: y + 58))
            NSAttributedString(string: option.label, attributes: titleAttributes)
                .draw(at: CGPoint(x: x + 82, y: y + 54))
        }
    }

    try savePNG(rep, to: outputURL)
}

let options: [IconOption] = [
    .init(fileName: "01_orbital-route.png", label: "Orbital Route", draw: drawOrbitalRoute),
    .init(fileName: "02_window-badge.png", label: "Window Badge", draw: drawWindowBadge),
    .init(fileName: "03_atlas-tile.png", label: "Atlas Tile", draw: drawAtlasTile),
    .init(fileName: "04_night-ring.png", label: "Night Ring", draw: drawNightRing),
    .init(fileName: "05_route-card.png", label: "Route Card", draw: drawRouteCard)
]

let fileManager = FileManager.default
let root = URL(fileURLWithPath: fileManager.currentDirectoryPath)
let outputDirectory = root.appendingPathComponent("design/icon-options", isDirectory: true)
try fileManager.createDirectory(at: outputDirectory, withIntermediateDirectories: true)

for option in options {
    let rep = renderBitmap(draw: option.draw)
    try savePNG(rep, to: outputDirectory.appendingPathComponent(option.fileName))
}

try drawComparisonSheet(
    options: options,
    imageDirectory: outputDirectory,
    outputURL: outputDirectory.appendingPathComponent("comparison-sheet.png")
)

print("Generated \(options.count) icons in \(outputDirectory.path)")
