import AppKit
import WebKit

/// `AlienHUD --snapshot <dir>` renders every palette to a PNG and quits.
///
/// The window is parked far off-screen so this never draws on the real display —
/// it's for checking the artwork without screenshotting whatever you're working on.
@MainActor
final class Snapshotter {
    private let outputDir: URL
    private var window: NSWindow?
    private var webView: WKWebView?
    private var remaining: [Palette] = Palette.all

    init(directory: String) {
        outputDir = URL(fileURLWithPath: (directory as NSString).expandingTildeInPath)
    }

    func run() {
        try? FileManager.default.createDirectory(at: outputDir,
                                                 withIntermediateDirectories: true)
        let size = NSSize(width: 1200, height: 700)
        // WebKit won't commit a layer tree for a window that isn't on a real display,
        // so this has to sit on screen — but at 2% opacity, behind everything, it's
        // effectively invisible for the couple of seconds it exists.
        let origin = NSScreen.main?.frame.origin ?? .zero
        let frame = NSRect(origin: origin, size: size)

        let web = WKWebView(frame: NSRect(origin: .zero, size: size))
        let win = NSWindow(contentRect: frame, styleMask: [.borderless],
                           backing: .buffered, defer: false)
        win.isOpaque = false
        win.backgroundColor = .clear
        win.alphaValue = 0.02
        win.level = .init(Int(CGWindowLevelForKey(.desktopIconWindow)))
        win.contentView = web
        win.orderBack(nil)
        window = win
        webView = web

        next()
    }

    private func next() {
        guard let palette = remaining.first, let web = webView else {
            NSApp.terminate(nil)
            return
        }
        remaining.removeFirst()

        web.loadHTMLString(
            Alien.html(eyebrow: Reminder.Kind.meeting.eyebrow,
                       line: "Strategy call with Bells in 5 minutes.",
                       scale: 1.4,
                       palette: palette),
            baseURL: nil)

        // 3.2s in: the ship has parked, head is up, bubble is open and typed.
        //
        // createPDF rather than takeSnapshot on purpose: snapshots come back blank for
        // a window that isn't on a real display, whereas the PDF path renders content
        // regardless of visibility.
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.2) { [weak self] in
            guard let self, let web = webView else { return }
            web.createPDF { result in
                switch result {
                case let .success(data): self.write(data, name: palette.name)
                case let .failure(error): NSLog("[AlienHUD] snapshot error: \(error)")
                }
                self.next()
            }
        }
    }

    private func write(_ pdf: Data, name: String) {
        let slug = name.lowercased().replacingOccurrences(of: " ", with: "-")
        let url = outputDir.appendingPathComponent("\(slug).pdf")
        try? pdf.write(to: url)
        NSLog("[AlienHUD] wrote \(url.path)")
    }
}
