// Compiles the ScreenCaptureKit Swift shim into a static library
// and weak-links the framework. Mirrors car-vision/build.rs.
//
// SCK is the macOS 14+ replacement for the deprecated CG capture
// APIs; weak-linking ScreenCaptureKit keeps the binary loadable on
// macOS 13 (where the runtime falls back to the CG path).

use std::env;
use std::path::PathBuf;
use std::process::Command;

fn shim_skipped(reason: String) {
    if std::env::var("CAR_REQUIRE_APPLE_SHIMS").as_deref() == Ok("1") {
        println!("cargo::error={reason}");
    } else {
        println!("cargo:warning={reason}");
        println!(
            "cargo:warning=ScreenCaptureKit shim skipped — display capture will use the \
             deprecated CGDisplayCreateImage path. Set CAR_REQUIRE_APPLE_SHIMS=1 to fail \
             the build instead."
        );
    }
}

fn main() {
    let target = env::var("TARGET").unwrap_or_default();
    let is_macos = target.ends_with("-apple-darwin");
    let is_apple_silicon = target.starts_with("aarch64-");

    println!("cargo::rustc-check-cfg=cfg(car_sck_swift_built)");
    println!("cargo:rerun-if-changed=swift/CarScreenCapture.swift");
    println!("cargo:rerun-if-changed=build.rs");

    if !is_macos {
        return;
    }

    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let swift_src = manifest_dir.join("swift").join("CarScreenCapture.swift");
    if !swift_src.exists() {
        shim_skipped(format!(
            "ScreenCaptureKit Swift shim not found at {}",
            swift_src.display()
        ));
        return;
    }

    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
    let obj_path = out_dir.join("CarScreenCapture.o");
    let lib_path = out_dir.join("libCarScreenCapture.a");

    // 14.0 floor: the SCK availability check inside the shim already
    // guards on macOS 14+. Compiling with a 14.0 target lets swiftc
    // resolve the SCK symbols at compile time without needing a
    // sub-version capability check around every call.
    let swift_target = if is_apple_silicon {
        "arm64-apple-macosx14.0"
    } else {
        "x86_64-apple-macosx14.0"
    };
    println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=14.0");

    let status = Command::new("xcrun")
        .arg("--sdk")
        .arg("macosx")
        .arg("swiftc")
        .arg("-parse-as-library")
        .arg("-O")
        .arg("-target")
        .arg(swift_target)
        .arg("-emit-object")
        .arg("-o")
        .arg(&obj_path)
        .arg(&swift_src)
        .status();

    let status = match status {
        Ok(s) => s,
        Err(e) => {
            shim_skipped(format!(
                "swiftc invocation failed ({e}); SCK backend unavailable. \
                 Install full Xcode (not just Command Line Tools) to enable it."
            ));
            return;
        }
    };
    if !status.success() {
        shim_skipped(format!(
            "swiftc returned non-zero status ({:?}); SCK backend unavailable",
            status.code()
        ));
        return;
    }

    let ar_status = Command::new("ar")
        .arg("crus")
        .arg(&lib_path)
        .arg(&obj_path)
        .status();
    match ar_status {
        Ok(s) if s.success() => {}
        _ => {
            shim_skipped(format!(
                "ar failed to pack {} into {}; SCK backend unavailable",
                obj_path.display(),
                lib_path.display()
            ));
            return;
        }
    }

    println!("cargo:rustc-link-search=native={}", out_dir.display());
    println!("cargo:rustc-link-lib=static=CarScreenCapture");

    // Weak-link ScreenCaptureKit so the binary still loads on macOS
    // 13 — the shim's runtime availability check returns 0 there
    // and the Rust caller falls back to the CG path.
    println!("cargo:rustc-link-arg=-Wl,-weak_framework,ScreenCaptureKit");
    println!("cargo:rustc-link-arg=-Wl,-framework,CoreVideo");
    println!("cargo:rustc-link-arg=-Wl,-framework,CoreGraphics");
    println!("cargo:rustc-link-arg=-Wl,-framework,Foundation");

    println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/swift");
    if let Ok(swift_lib) = swift_runtime_path() {
        println!("cargo:rustc-link-search=native={}", swift_lib);
    }
    println!("cargo:rustc-link-lib=dylib=swiftCore");
    println!("cargo:rustc-link-lib=dylib=swift_Concurrency");
    println!("cargo:rustc-link-lib=dylib=swiftFoundation");

    println!("cargo:rustc-cfg=car_sck_swift_built");
}

fn swift_runtime_path() -> Result<String, std::io::Error> {
    let out = Command::new("xcrun").arg("--show-sdk-path").output()?;
    if !out.status.success() {
        return Err(std::io::Error::other("xcrun --show-sdk-path failed"));
    }
    let sdk = String::from_utf8_lossy(&out.stdout).trim().to_string();
    Ok(format!("{}/usr/lib/swift", sdk))
}
