//! Build script for blue-ollama
//!
//! Downloads Ollama binary for the target platform at build time.
//! Set BLUE_OLLAMA_PATH to skip download and use a local binary.
//! Set BLUE_SKIP_OLLAMA_DOWNLOAD=1 to skip download entirely.

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};

/// Ollama version to download
const OLLAMA_VERSION: &str = "v0.5.4";

/// Base URL for Ollama releases
const OLLAMA_RELEASE_URL: &str = "https://github.com/ollama/ollama/releases/download";

fn main() {
    println!("cargo:rerun-if-env-changed=BLUE_OLLAMA_PATH");
    println!("cargo:rerun-if-env-changed=BLUE_SKIP_OLLAMA_DOWNLOAD");

    // Skip if BLUE_OLLAMA_PATH is set (user provides their own binary)
    if env::var("BLUE_OLLAMA_PATH").is_ok() {
        println!("cargo:warning=Using BLUE_OLLAMA_PATH, skipping Ollama download");
        return;
    }

    // Skip if explicitly disabled
    if env::var("BLUE_SKIP_OLLAMA_DOWNLOAD").is_ok() {
        println!("cargo:warning=BLUE_SKIP_OLLAMA_DOWNLOAD set, skipping Ollama download");
        return;
    }

    // Get output directory
    let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
    let out_path = PathBuf::from(&out_dir);

    // Determine target platform
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();

    let (binary_name, download_url) = match (target_os.as_str(), target_arch.as_str()) {
        ("macos", _) => (
            "ollama",
            format!("{}/{}/ollama-darwin", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
        ),
        ("linux", "x86_64") => (
            "ollama",
            format!("{}/{}/ollama-linux-amd64", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
        ),
        ("linux", "aarch64") => (
            "ollama",
            format!("{}/{}/ollama-linux-arm64", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
        ),
        ("windows", "x86_64") => (
            "ollama.exe",
            format!("{}/{}/ollama-windows-amd64.exe", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
        ),
        _ => {
            println!("cargo:warning=Unsupported platform: {}-{}", target_os, target_arch);
            println!("cargo:warning=Ollama will need to be installed manually");
            return;
        }
    };

    let binary_path = out_path.join(binary_name);

    // Check if already downloaded
    if binary_path.exists() {
        println!("cargo:warning=Ollama binary already exists at {:?}", binary_path);
        write_binary_path(&out_path, &binary_path);
        return;
    }

    // Download the binary
    println!("cargo:warning=Downloading Ollama {} for {}-{}", OLLAMA_VERSION, target_os, target_arch);
    println!("cargo:warning=URL: {}", download_url);

    match download_binary(&download_url, &binary_path) {
        Ok(_) => {
            println!("cargo:warning=Downloaded Ollama to {:?}", binary_path);

            // Make executable on Unix
            #[cfg(unix)]
            {
                use std::os::unix::fs::PermissionsExt;
                if let Ok(metadata) = fs::metadata(&binary_path) {
                    let mut perms = metadata.permissions();
                    perms.set_mode(0o755);
                    let _ = fs::set_permissions(&binary_path, perms);
                }
            }

            write_binary_path(&out_path, &binary_path);
        }
        Err(e) => {
            println!("cargo:warning=Failed to download Ollama: {}", e);
            println!("cargo:warning=Ollama will need to be installed manually");
            println!("cargo:warning=Install with: brew install ollama (macOS) or see https://ollama.ai");
        }
    }
}

/// Download binary using reqwest (blocking)
fn download_binary(url: &str, dest: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::blocking::Client::builder()
        .timeout(std::time::Duration::from_secs(300))
        .build()?;

    let response = client.get(url).send()?;

    if !response.status().is_success() {
        return Err(format!("HTTP {}: {}", response.status(), url).into());
    }

    let bytes = response.bytes()?;
    let mut file = File::create(dest)?;
    file.write_all(&bytes)?;

    Ok(())
}

/// Write the binary path to a file for runtime discovery
fn write_binary_path(out_dir: &Path, binary_path: &Path) {
    let path_file = out_dir.join("ollama_binary_path.txt");
    if let Ok(mut file) = File::create(&path_file) {
        let _ = writeln!(file, "{}", binary_path.display());
    }
}
