import AppKit
import CoreGraphics
import AlignerCore

struct SystemCriticalWindowRecord: Equatable {
    let ownerName: String
    let title: String
    let processIdentifier: Int32
    let layer: Int
    let bounds: CGRect
}

protocol SystemCriticalWindowDetecting: AnyObject {
    func visibleSystemCriticalWindows() -> [SystemCriticalWindowRecord]
}

final class CGWindowSystemCriticalWindowDetector: SystemCriticalWindowDetecting {
    func visibleSystemCriticalWindows() -> [SystemCriticalWindowRecord] {
        guard let windowInfo = CGWindowListCopyWindowInfo(
            [.optionOnScreenOnly, .excludeDesktopElements],
            kCGNullWindowID
        ) as? [[String: Any]] else {
            return []
        }

        return windowInfo.compactMap { rawWindow in
            let ownerName = stringValue(rawWindow[kCGWindowOwnerName as String]) ?? ""
            guard ownerName != "Aligner" else { return nil }

            let title = stringValue(rawWindow[kCGWindowName as String]) ?? ""
            let descriptor = SystemCriticalWindowDescriptor(ownerName: ownerName, title: title)
            guard SystemCriticalWindowClassifier.isSystemCritical(descriptor) else {
                return nil
            }

            let bounds = rectValue(rawWindow[kCGWindowBounds as String])
            guard bounds.width > 0, bounds.height > 0 else { return nil }

            return SystemCriticalWindowRecord(
                ownerName: ownerName,
                title: title,
                processIdentifier: Int32(intValue(rawWindow[kCGWindowOwnerPID as String])),
                layer: intValue(rawWindow[kCGWindowLayer as String]),
                bounds: bounds
            )
        }
    }

    private func stringValue(_ value: Any?) -> String? {
        value as? String
    }

    private func intValue(_ value: Any?) -> Int {
        switch value {
        case let number as NSNumber:
            return number.intValue
        case let int as Int:
            return int
        default:
            return 0
        }
    }

    private func doubleValue(_ value: Any?) -> Double {
        switch value {
        case let number as NSNumber:
            return number.doubleValue
        case let double as Double:
            return double
        case let int as Int:
            return Double(int)
        default:
            return 0
        }
    }

    private func rectValue(_ value: Any?) -> CGRect {
        guard let dictionary = value as? [String: Any] else {
            return .zero
        }

        return CGRect(
            x: doubleValue(dictionary["X"]),
            y: doubleValue(dictionary["Y"]),
            width: doubleValue(dictionary["Width"]),
            height: doubleValue(dictionary["Height"])
        )
    }
}
