import Foundation
import RealityKit

// Uso: oc <carpeta_imagenes> <salida.usdz> [detail: preview|reduced|medium|full|raw]
guard CommandLine.arguments.count >= 3 else {
    FileHandle.standardError.write("uso: oc <carpeta_imagenes> <salida.usdz> [detail]\n".data(using: .utf8)!)
    exit(2)
}
let inputURL = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
let outputURL = URL(fileURLWithPath: CommandLine.arguments[2])
let detailArg = CommandLine.arguments.count >= 4 ? CommandLine.arguments[3] : "full"

guard #available(macOS 12.0, *), PhotogrammetrySession.isSupported else {
    FileHandle.standardError.write("Object Capture no soportado en este equipo.\n".data(using: .utf8)!)
    exit(1)
}

func detailFrom(_ s: String) -> PhotogrammetrySession.Request.Detail {
    switch s.lowercased() {
    case "preview": return .preview
    case "reduced": return .reduced
    case "medium": return .medium
    case "raw": return .raw
    default: return .full
    }
}

func log(_ s: String) { FileHandle.standardError.write((s + "\n").data(using: .utf8)!) }

var config = PhotogrammetrySession.Configuration()
config.sampleOrdering = .sequential          // fotogramas de un vídeo orbital
config.featureSensitivity = .high            // ayuda con superficies de poca textura

do {
    let session = try PhotogrammetrySession(input: inputURL, configuration: config)
    let request = PhotogrammetrySession.Request.modelFile(url: outputURL, detail: detailFrom(detailArg))
    let sem = DispatchSemaphore(value: 0)
    var failed = false

    Task {
        do {
            for try await output in session.outputs {
                switch output {
                case .requestProgress(_, let f):
                    log("progress \(Int(f * 100))%")
                case .requestComplete(_, let result):
                    if case .modelFile(let url) = result {
                        log("MODEL_WRITTEN \(url.path)")
                    }
                case .requestError(_, let error):
                    log("REQUEST_ERROR \(error)"); failed = true; sem.signal()
                case .processingComplete:
                    log("PROCESSING_COMPLETE"); sem.signal()
                case .processingCancelled:
                    log("CANCELLED"); failed = true; sem.signal()
                case .invalidSample(let id, let reason):
                    log("invalidSample \(id): \(reason)")
                case .inputComplete:
                    log("input_complete")
                case .automaticDownsampling:
                    log("automatic_downsampling")
                default:
                    break
                }
            }
        } catch {
            log("OUTPUT_STREAM_ERROR \(error)"); failed = true; sem.signal()
        }
    }

    log("procesando \(detailArg) desde \(inputURL.path) ...")
    try session.process(requests: [request])
    sem.wait()
    exit(failed ? 1 : 0)
} catch {
    log("FATAL \(error)")
    exit(1)
}
