import Foundation
import Vision
import ArgumentParser
import AppKit

/// POC: Test Apple Vision Framework for object detection (YOLO replacement)
@main
struct VisionObjectTest: ParsableCommand {
    @Argument(help: "Input image path")
    var inputPath: String

    func run() throws {
        let startTime = Date()
        print("=== Apple Vision Framework Object Detection POC ===")
        #if arch(arm64)
        print("HW: Apple Silicon ✅ (ANE available)")
        #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. VNClassifyImageRequest (scene classification - replaces scene_classifier)
        print("\n--- VNClassifyImageRequest ---")
        let clsReq = VNClassifyImageRequest()
        try handler.perform([clsReq])
        if let classifications = clsReq.results {
            print("Top classifications:")
            for c in classifications.prefix(10) {
                print("  \(c.identifier): conf=\(String(format: "%.3f", c.confidence))")
            }
        }

        // 2. VNDetectHumanRectanglesRequest (person detection - YOLO replacement for 'person')
        print("\n--- VNDetectHumanRectanglesRequest ---")
        let humanReq = VNDetectHumanRectanglesRequest()
        try handler.perform([humanReq])
        if let humans = humanReq.results {
            print("Humans: \(humans.count)")
            for (i, h) in humans.enumerated() {
                let bb = h.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", h.confidence))")
            }
        }

        // 3. VNDetectHumanBodyPoseRequest (pose estimation - MediaPipe replacement)
        print("\n--- VNDetectHumanBodyPoseRequest ---")
        let poseReq = VNDetectHumanBodyPoseRequest()
        try handler.perform([poseReq])
        if let poses = poseReq.results {
            print("Body poses: \(poses.count)")
            for (i, p) in poses.enumerated() {
                let joints = p.availableJointNames
                print("  [\(i)] \(joints.count) joints detected")
                // Show key joints
                for joint in [VNHumanBodyPoseObservation.JointName.neck,
                              VNHumanBodyPoseObservation.JointName.leftShoulder,
                              VNHumanBodyPoseObservation.JointName.rightShoulder,
                              VNHumanBodyPoseObservation.JointName.leftWrist,
                              VNHumanBodyPoseObservation.JointName.rightWrist,
                              VNHumanBodyPoseObservation.JointName.root] {
                    if let pt = try? p.recognizedPoint(joint) {
                        print("    \(joint.rawValue): (\(String(format: "%.3f", pt.location.x)), \(String(format: "%.3f", pt.location.y))) conf=\(String(format: "%.2f", pt.confidence))")
                    }
                }
            }
        }

        // 4. VNDetectHumanHandPoseRequest (hand pose)
        print("\n--- VNDetectHumanHandPoseRequest ---")
        let handReq = VNDetectHumanHandPoseRequest()
        try handler.perform([handReq])
        if let hands = handReq.results {
            print("Hands: \(hands.count)")
            for (i, h) in hands.enumerated() {
                print("  [\(i)] confidence=\(String(format: "%.2f", h.confidence))")
            }
        }

        // 5. VNGenerateObjectnessBasedSaliencyImageRequest (object detection without labels)
        print("\n--- VNGenerateObjectnessBasedSaliencyImageRequest ---")
        let salReq = VNGenerateObjectnessBasedSaliencyImageRequest()
        try handler.perform([salReq])
        if let sal = salReq.results?.first {
            if let objects = sal.salientObjects {
                print("Salient objects: \(objects.count)")
                for (i, ob) in objects.enumerated().prefix(10) {
                    let bb = ob.boundingBox
                    print("  [\(i)] bbox=(\(String(format: "%.3f", bb.origin.x)),\(String(format: "%.3f", bb.origin.y)),\(String(format: "%.3f", bb.size.width)),\(String(format: "%.3f", bb.size.height))) conf=\(String(format: "%.2f", ob.confidence))")
                }
            }
        }

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