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

fn main() {
    // Only build Vision bridge on macOS
    if env::var("CARGO_CFG_TARGET_OS").unwrap() != "macos" {
        return;
    }

    println!("cargo:rerun-if-changed=vision-bridge/Sources/VisionBridge/VisionOCR.swift");
    println!("cargo:rerun-if-changed=vision-bridge/Sources/VisionBridge/VisionBridge.h");
    println!("cargo:rerun-if-changed=vision-bridge/Package.swift");

    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let vision_bridge_dir = manifest_dir.join("vision-bridge");

    // Build Swift package
    println!("cargo:warning=Building VisionBridge Swift package...");
    let build_status = Command::new("swift")
        .args(&["build", "-c", "release"])
        .current_dir(&vision_bridge_dir)
        .status()
        .expect("Failed to build Swift package");

    if !build_status.success() {
        panic!("Swift build failed");
    }

    // Find the built library
    let lib_path = vision_bridge_dir
        .join(".build/release")
        .canonicalize()
        .expect("Failed to find .build/release directory");

    // Copy the dylib to the output directory so it can be found at runtime
    let target_dir = manifest_dir
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .join("target");
    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());

    // Determine the actual target directory (could be llvm-cov-target or regular target)
    let target_dir_name =
        env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| target_dir.to_string_lossy().to_string());
    let actual_target_dir = PathBuf::from(&target_dir_name);
    let output_dir = actual_target_dir.join(&profile);

    let dylib_src = lib_path.join("libVisionBridge.dylib");
    let dylib_dst = output_dir.join("libVisionBridge.dylib");

    // Create output directory if it doesn't exist
    std::fs::create_dir_all(&output_dir).expect(&format!(
        "Failed to create output directory {}",
        output_dir.display()
    ));

    std::fs::copy(&dylib_src, &dylib_dst).expect(&format!(
        "Failed to copy dylib from {} to {}",
        dylib_src.display(),
        dylib_dst.display()
    ));

    println!(
        "cargo:warning=Copied libVisionBridge.dylib to {}",
        dylib_dst.display()
    );

    // Re-sign the dylib with ad-hoc signature to fix code signing issues on Apple Silicon
    // This is necessary because incremental compilation can invalidate signatures
    let codesign_status = Command::new("codesign")
        .args(&["-f", "-s", "-", dylib_dst.to_str().unwrap()])
        .status();

    if let Ok(status) = codesign_status {
        if !status.success() {
            println!("cargo:warning=Failed to codesign libVisionBridge.dylib (non-fatal)");
        }
    }

    // Add rpath so the dylib can be found at runtime
    println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path");
    println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
    println!("cargo:rustc-link-lib=dylib=VisionBridge");

    // Link required frameworks
    println!("cargo:rustc-link-lib=framework=Vision");
    println!("cargo:rustc-link-lib=framework=AppKit");
    println!("cargo:rustc-link-lib=framework=Foundation");
    println!("cargo:rustc-link-lib=framework=CoreGraphics");
    println!("cargo:rustc-link-lib=framework=CoreImage");

    println!(
        "cargo:warning=VisionBridge built successfully at {}",
        lib_path.display()
    );
}
