import AppKit

@MainActor
private final class PulseView: NSView {
    var pulse = 0 {
        didSet { needsDisplay = true }
    }

    var onEvent: ((String) -> Void)?

    override var acceptsFirstResponder: Bool { true }

    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        NSColor(calibratedWhite: 0.10, alpha: 1).setFill()
        dirtyRect.fill()

        let progress = CGFloat(pulse % 20) / 19
        let diameter: CGFloat = 34 + progress * 68
        let rect = NSRect(
            x: bounds.midX - diameter / 2,
            y: bounds.midY - diameter / 2,
            width: diameter,
            height: diameter
        )
        NSColor.systemOrange.setFill()
        NSBezierPath(ovalIn: rect).fill()

        let label = "run-loop pulse \(pulse)" as NSString
        label.draw(
            at: NSPoint(x: 16, y: 14),
            withAttributes: [
                .font: NSFont.monospacedSystemFont(ofSize: 12, weight: .medium),
                .foregroundColor: NSColor.white,
            ]
        )
    }

    override func mouseDown(with event: NSEvent) {
        window?.makeFirstResponder(self)
        onEvent?("mouseDown → PulseView became first responder")
    }

    override func keyDown(with event: NSEvent) {
        onEvent?("keyDown → \(event.charactersIgnoringModifiers ?? "unknown")")
        super.keyDown(with: event)
    }
}

@MainActor
private final class AppDelegate: NSObject, NSApplicationDelegate {
    private var window: NSWindow!
    private let pulseView = PulseView(frame: .zero)
    private let eventLog = NSTextView(frame: .zero)
    private var timer: Timer?
    private var worker: Task<Void, Never>?

    func applicationDidFinishLaunching(_ notification: Notification) {
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 720, height: 620),
            styleMask: [.titled, .closable, .miniaturizable, .resizable],
            backing: .buffered,
            defer: false
        )
        window.title = "Apple Interview OS Workbench · Event Loop"
        window.center()

        let title = NSTextField(labelWithString: "Watch the main run loop breathe.")
        title.font = .systemFont(ofSize: 26, weight: .bold)
        let subtitle = NSTextField(wrappingLabelWithString: "The pulse, event routing, layout, and drawing all depend on the main thread returning to AppKit.")
        subtitle.textColor = .secondaryLabelColor

        pulseView.wantsLayer = true
        pulseView.layer?.cornerRadius = 10
        pulseView.heightAnchor.constraint(equalToConstant: 210).isActive = true
        pulseView.onEvent = { [weak self] message in self?.append(message) }

        let blockButton = NSButton(title: "Block main thread · 600 ms", target: self, action: #selector(blockMainThread))
        blockButton.bezelStyle = .rounded
        let asyncButton = NSButton(title: "Run work off main thread", target: self, action: #selector(runAsync))
        asyncButton.bezelStyle = .rounded
        let buttons = NSStackView(views: [blockButton, asyncButton])
        buttons.orientation = .horizontal
        buttons.spacing = 10

        eventLog.isEditable = false
        eventLog.font = .monospacedSystemFont(ofSize: 12, weight: .regular)
        eventLog.string = "Click the pulse, press a key, then compare the two buttons.\n"
        let scroll = NSScrollView()
        scroll.hasVerticalScroller = true
        scroll.borderType = .bezelBorder
        scroll.documentView = eventLog
        scroll.heightAnchor.constraint(equalToConstant: 170).isActive = true

        let stack = NSStackView(views: [title, subtitle, pulseView, buttons, scroll])
        stack.orientation = .vertical
        stack.alignment = .leading
        stack.spacing = 14
        stack.edgeInsets = NSEdgeInsets(top: 26, left: 28, bottom: 26, right: 28)
        stack.translatesAutoresizingMaskIntoConstraints = false
        pulseView.widthAnchor.constraint(equalTo: stack.widthAnchor, constant: -56).isActive = true
        scroll.widthAnchor.constraint(equalTo: stack.widthAnchor, constant: -56).isActive = true

        let root = NSView()
        root.addSubview(stack)
        NSLayoutConstraint.activate([
            stack.leadingAnchor.constraint(equalTo: root.leadingAnchor),
            stack.trailingAnchor.constraint(equalTo: root.trailingAnchor),
            stack.topAnchor.constraint(equalTo: root.topAnchor),
            stack.bottomAnchor.constraint(lessThanOrEqualTo: root.bottomAnchor),
        ])
        window.contentView = root
        window.makeKeyAndOrderFront(nil)
        NSApp.activate(ignoringOtherApps: true)
        window.makeFirstResponder(pulseView)

        timer = Timer(timeInterval: 0.10, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
        RunLoop.main.add(timer!, forMode: .common)
        append("applicationDidFinishLaunching → main run loop active")
    }

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true }

    func applicationWillTerminate(_ notification: Notification) {
        worker?.cancel()
    }

    @objc private func tick() {
        pulseView.pulse += 1
    }

    @objc private func blockMainThread() {
        append("BROKEN → blocking main thread for 600 ms")
        Thread.sleep(forTimeInterval: 0.60)
        append("main thread returned; queued UI work can continue")
    }

    @objc private func runAsync() {
        worker?.cancel()
        append("FIXED → cancellable CPU work started off the main actor")
        worker = Task { @MainActor [weak self] in
            let computation: Task<UInt64?, Never> = Task.detached(priority: .userInitiated) {
                let deadline = ContinuousClock.now.advanced(by: .milliseconds(600))
                var checksum: UInt64 = 0

                while ContinuousClock.now < deadline {
                    for value in 1...50_000 {
                        checksum = checksum &* 1_664_525 &+ UInt64(value)
                    }
                    if Task.isCancelled { return nil }
                }
                return checksum
            }

            let checksum = await withTaskCancellationHandler {
                await computation.value
            } onCancel: {
                computation.cancel()
            }

            guard let checksum else {
                self?.append("background CPU work cancelled")
                return
            }
            self?.append("background CPU result delivered on MainActor · checksum \(checksum)")
        }
    }

    private func append(_ message: String) {
        let stamp = String(format: "%.3f", ProcessInfo.processInfo.systemUptime)
        eventLog.string += "[\(stamp)] \(message)\n"
        eventLog.scrollToEndOfDocument(nil)
    }
}

let application = NSApplication.shared
private let delegate = AppDelegate()
application.delegate = delegate
application.setActivationPolicy(.regular)
application.run()
