import Foundation
import Vision
import ArgumentParser
import AppKit

/// POC: Test Apple Vision Framework for face detection + faceprint extraction
@main
struct FaceVisionTest: ParsableCommand {
    @Argument(help: "Input image path")
    var inputPath: String

    mutating func run() throws {
        let startTime = Date()
        print("=== Apple Vision Framework Face POC ===")
        #if arch(arm64)
        print("HW: Apple Silicon ✅")
        #else
        print("HW: Intel")
        #endif

        guard let image = NSImage(contentsOfFile: inputPath) else {
            print("Error: cannot load image"); return
        }
        guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
            print("Error: cannot get CGImage"); return
        }
        print("Image: \(cgImage.width)x\(cgImage.height)")
        let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])

        // 1. Detect faces (synchronous)
        print("\n--- Detection ---")
        let detectReq = VNDetectFaceRectanglesRequest()
        try handler.perform([detectReq])
        let faces = detectReq.results ?? []
        print("Faces: \(faces.count)")
        for (i, f) in faces.enumerated() {
            let bb = f.boundingBox
            print("  [\(i)] bbox=(\(String(format: "%.3f", bb.origin.x)),\(String(format: "%.3f", bb.origin.y))) size=(\(String(format: "%.3f", bb.size.width)),\(String(format: "%.3f", bb.size.height))) conf=\(String(format: "%.2f", f.confidence))")
        }

        guard !faces.isEmpty else { print("No faces"); return }

        // 2. Landmarks
        print("\n--- Landmarks ---")
        let lmReq = VNDetectFaceLandmarksRequest()
        try handler.perform([lmReq])
        if let lmResults = lmReq.results {
            for (i, f) in lmResults.enumerated() {
                if let lms = f.landmarks {
                    let count = (lms.leftEye?.pointCount ?? 0) + (lms.rightEye?.pointCount ?? 0)
                    print("  [\(i)] landmarks: \(lms.leftEye?.pointCount ?? 0)+\(lms.rightEye?.pointCount ?? 0) eye pts, nose=\(lms.nose?.pointCount ?? 0)")
                }
            }
        }

        // 3. Capture quality
        print("\n--- Capture Quality ---")
        let qualReq = VNDetectFaceCaptureQualityRequest()
        try handler.perform([qualReq])
        if let qResults = qualReq.results {
            for (i, f) in qResults.enumerated() {
                if #available(macOS 14, *) {
                    let q = f.value(forKey: "faceCaptureQuality") as? Double ?? -1
                    print("  [\(i)] quality=\(String(format: "%.4f", q))")
                }
            }
        }

        // 4. Faceprint (embedding)
        print("\n--- Faceprint ---")
        if #available(macOS 14, *) {
            let fpClass: AnyClass? = NSClassFromString("VNFaceprint")
            print("VNFaceprint class: \(fpClass != nil ? "✅ exists" : "❌ nil")")

            if let first = faces.first {
                let fp = first.value(forKey: "faceprint") as? NSObject
                print("faceprint KVC: \(fp != nil ? "✅" : "❌")")
                if let fpData = fp {
                    let data = fpData.value(forKey: "data") as? Data
                    print("  data: \(data != nil ? "\(data!.count) bytes" : "nil")")
                    let desc = fpData.value(forKey: "descriptor") as? NSObject
                    print("  descriptor: \(desc != nil ? "✅ class=\(type(of: desc!))" : "nil")")
                    if let d = desc, let elems = d.value(forKey: "elements") as? [NSNumber] {
                        print("  elements: \(elems.count) dims")
                        if elems.count > 0 {
                            print("  first 5: \(elems.prefix(5).map { String(format: "%.4f", $0.doubleValue) }.joined(separator: ", "))")
                        }
                    }
                }
            }
        } else {
            print("macOS 14+ required")
        }

        print("\nTime: \(String(format: "%.2f", Date().timeIntervalSince(startTime)))s")
        print("=== Done ===")
    }
}
