import MLKitFaceDetection
import MLKitVision
import NitroModules
import VisionCamera

class HybridFaceScanner: HybridFaceScannerSpec {
  private let orientationManager = FaceDetectorOrientation()
  private let runLandmarks: Bool
  private let runContours: Bool
  private let runClassifications: Bool
  private let trackingEnabled: Bool
  private let autoMode: Bool
  private let cameraFacing: CameraPosition
  private let windowWidth: Double
  private let windowHeight: Double
  private let faceDetector: FaceDetector
  
  init(options: FaceScannerOptions) {
    self.runLandmarks = options.runLandmarks ?? false
    self.runContours = options.runContours ?? false
    self.runClassifications = options.runClassifications ?? false
    self.trackingEnabled = options.trackingEnabled ?? false
    self.autoMode = options.autoMode ?? false
    self.cameraFacing = options.cameraFacing ?? .front
    self.windowWidth = options.windowWidth ?? 1.0
    self.windowHeight = options.windowHeight ?? 1.0
    self.faceDetector = FaceDetector.faceDetector(
      options: options.toMLFaceDetectorOptions()
    )
    super.init()
  }
  
  func scanFaces(
    frame: any HybridFrameSpec
  ) throws -> [any HybridFaceSpec] {
    let image = try frame.toMLImage(
      orientation: orientationManager.orientation,
      cameraFacing: cameraFacing
    )
    var width = CGFloat(frame.width)
    var height = CGFloat(frame.height)
    if(width > height) {
      width = CGFloat(frame.height)
      height = CGFloat(frame.width)
    }
    let config = FaceProcessConfig(
      width: width,
      height: height,
      scaleX: autoMode ? windowWidth / width : 1.0,
      scaleY: autoMode ? windowHeight / height : 1.0,
      runLandmarks: runLandmarks,
      runContours: runContours,
      runClassifications: runClassifications,
      trackingEnabled: trackingEnabled,
      autoMode: autoMode,
      cameraFacing: cameraFacing,
      orientation: orientationManager.orientation
    )
    
    let faces = try faceDetector.results(in: image)
    return faces.map {
      HybridFace(
        face: $0,
        config: config,
        base64: nil,
        data: nil,
        message: "Successfully Get Face"
      )
    }
  }
}
