#![allow(clippy::expect_used, clippy::unwrap_used)]

use std::env;
use std::fs;
use std::io::Write;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=src/installer/mod.rs");
    println!("cargo:rerun-if-changed=../scripts/install.sh");
    println!("cargo:rerun-if-changed=assets/vendor/");
    println!("cargo:rerun-if-changed=assets/demo/");
    println!("cargo:rerun-if-changed=../assets/demo/");
    println!("cargo:rerun-if-changed=templates/");
    println!("cargo:rerun-if-changed=src/schema/refactor_state.capnp");

    // Declare custom cfg flags
    println!("cargo:rustc-check-cfg=cfg(cargo_publish)");
    println!("cargo:rustc-check-cfg=cfg(coverage)");

    // Fast build mode for development - skip heavy operations
    if env::var("PMAT_FAST_BUILD").is_ok() {
        println!("cargo:warning=Fast build mode enabled - skipping heavy build operations");
        return;
    }

    // Verify critical dependencies at build time
    verify_dependency_versions();

    // Compress templates at build time
    compress_templates();

    // Download and compress assets for demo mode
    // Skip asset downloading during cargo publish to avoid modifying source directory
    if env::var("CARGO_FEATURE_DEMO").is_ok() && !is_publishing() {
        download_and_compress_assets();
        minify_demo_assets();
    }

    // Compile Cap'n Proto schema for MCP server
    // compile_capnp_schema(); // REMOVED: Cap'n Proto dependency eliminated (unused bloat)

    // Generate MCP discovery optimization tables
    // Skip during coverage builds to prevent hangs
    if env::var("CARGO_LLVM_COV").is_err() && env::var("SKIP_MCP_TABLES").is_err() {
        generate_mcp_discovery_tables();
    } else {
        println!("cargo:warning=Skipping MCP discovery table generation (coverage build or SKIP_MCP_TABLES set)");
        // Generate stub files to allow compilation
        let out_dir = env::var("OUT_DIR").expect("OUT_DIR must be set");
        generate_stub_files(&out_dir);
    }
}

/// Check if we're in a cargo publish context
fn is_publishing() -> bool {
    // During cargo publish, the package is extracted to a temp directory
    let is_publish = env::var("CARGO_PKG_VERSION").is_ok()
        && env::current_dir()
            .map(|dir| dir.to_string_lossy().contains("/target/package/"))
            .unwrap_or(false);

    if is_publish {
        println!("cargo:rustc-cfg=cargo_publish");
    }

    is_publish
}

/// Verifies critical dependencies exist in Cargo.lock
///
/// # Panics
///
/// Panics if Cargo.lock doesn't exist or critical dependencies are missing
fn verify_dependency_versions() {
    // In a workspace, Cargo.lock is in the parent directory
    let lock_path = if Path::new("../Cargo.lock").exists() {
        "../Cargo.lock"
    } else {
        "Cargo.lock"
    };
    let lock_content = fs::read_to_string(lock_path).expect("Cargo.lock must exist");

    // Critical dependencies for your MCP server
    let critical_deps = [
        "tokio",      // Async runtime
        "serde",      // Serialization
        "handlebars", // Template engine
    ];

    for dep in &critical_deps {
        assert!(
            lock_content.contains(&format!("name = \"{dep}\"")),
            "Critical dependency {dep} not found"
        );
    }
}

fn download_and_compress_assets() {
    setup_asset_directories();
    let assets = get_asset_definitions();
    process_assets(&assets);
    set_asset_hash_env();
}

fn setup_asset_directories() {
    let vendor_dir = Path::new("assets/vendor");
    let demo_dir = Path::new("assets/demo");
    let _ = fs::create_dir_all(vendor_dir);
    let _ = fs::create_dir_all(demo_dir);
}

const fn get_asset_definitions() -> [(&'static str, &'static str); 4] {
    [
        (
            "https://unpkg.com/gridjs@6.0.6/dist/gridjs.umd.js",
            "gridjs.min.js",
        ),
        (
            "https://unpkg.com/gridjs@6.0.6/dist/theme/mermaid.min.css",
            "gridjs-mermaid.min.css",
        ),
        (
            "https://unpkg.com/mermaid@latest/dist/mermaid.min.js",
            "mermaid.min.js",
        ),
        ("https://unpkg.com/d3@latest/dist/d3.min.js", "d3.min.js"),
    ]
}

fn process_assets(assets: &[(&str, &str)]) {
    let vendor_dir = Path::new("assets/vendor");

    for (url, filename) in assets {
        let path = vendor_dir.join(filename);
        let gz_path = vendor_dir.join(format!("{filename}.gz"));
        let hash_path = vendor_dir.join(format!("{filename}.hash"));

        if should_skip_asset(&path, &gz_path, &hash_path) {
            println!("cargo:warning=Skipping unchanged asset: {filename} (O(1) hash check)");
            continue;
        }

        ensure_asset_downloaded(&path, &gz_path, url, filename);
        compress_asset(&path, &gz_path, &hash_path, filename);
    }
}

fn should_skip_asset(source_path: &Path, gz_path: &Path, hash_path: &Path) -> bool {
    // O(1) optimization: Skip if output exists AND source hasn't changed
    if !gz_path.exists() || !source_path.exists() {
        return false;
    }

    // Hash-based check: O(1) for unchanged files
    !has_file_changed(source_path, hash_path)
}

fn ensure_asset_downloaded(path: &Path, gz_path: &Path, url: &str, filename: &str) {
    if !path.exists() {
        // Check if we're in a docs.rs build environment
        if env::var("DOCS_RS").is_ok() {
            println!("cargo:warning=Skipping asset download in docs.rs environment: {filename}");
            // Create a placeholder file for docs.rs builds
            let _ = fs::write(path, b"/* Asset skipped in docs.rs build */");
            // Also create an empty gzipped placeholder to satisfy include_bytes!
            let _ = fs::write(gz_path, b"");
        } else {
            download_asset(url, path, filename);
        }
    }
}

fn download_asset(url: &str, path: &Path, filename: &str) {
    println!("cargo:warning=Downloading {filename} from {url}");

    match ureq::get(url).call() {
        Ok(mut response) => match response.body_mut().read_to_vec() {
            Ok(content) => {
                if let Err(e) = fs::write(path, &content) {
                    println!("cargo:warning=Failed to write {filename}: {e}");
                }
            }
            Err(e) => {
                println!("cargo:warning=Failed to read {filename}: {e}");
                let _ = fs::write(path, b"/* Asset download failed during build */");
            }
        },
        Err(e) => {
            handle_download_failure(&e, path, filename);
        }
    }
}

fn handle_download_failure(e: &ureq::Error, path: &Path, filename: &str) {
    println!("cargo:warning=Failed to download {filename}: {e}. Using placeholder.");
    // Create a placeholder file
    let _ = fs::write(path, b"/* Asset download failed during build */");
}

fn compress_asset(path: &Path, gz_path: &Path, hash_path: &Path, filename: &str) {
    if !path.exists() {
        return;
    }

    let Ok(input) = fs::read(path) else { return };

    let Some(compressed) = create_compressed_data(&input) else {
        return;
    };

    write_compressed_file(gz_path, &compressed, filename, input.len());

    // Save hash for O(1) skip detection on next build
    if let Some(hash) = calculate_file_hash(path) {
        let _ = write_hash_file(hash_path, &hash);
    }
}

fn create_compressed_data(input: &[u8]) -> Option<Vec<u8>> {
    use flate2::write::GzEncoder;
    use flate2::Compression;

    let mut encoder = GzEncoder::new(Vec::new(), Compression::best());
    encoder.write_all(input).ok()?;
    encoder.finish().ok()
}

fn write_compressed_file(gz_path: &Path, compressed: &[u8], filename: &str, original_size: usize) {
    if fs::write(gz_path, compressed).is_ok() {
        if let Ok(metadata) = fs::metadata(gz_path) {
            println!(
                "cargo:warning=Compressed {} ({} -> {} bytes)",
                filename,
                original_size,
                metadata.len()
            );
        }
    }
}

fn set_asset_hash_env() {
    let hash = calculate_asset_hash();
    println!("cargo:rustc-env=ASSET_HASH={hash}");
}

/// Compresses template files at build time
///
/// # Panics
///
/// Panics if `OUT_DIR` environment variable is not set
fn compress_templates() {
    let templates_dir = Path::new("templates");

    if !validate_templates_directory(templates_dir) {
        return;
    }

    // O(1) optimization: Skip if templates haven't changed
    let out_dir = env::var("OUT_DIR").expect("OUT_DIR must be set");
    let hash_path = Path::new(&out_dir).join("templates.hash");

    if let Some(current_hash) = calculate_templates_hash(templates_dir) {
        if hash_path.exists() {
            if let Some(stored_hash) = read_stored_hash(&hash_path) {
                if current_hash == stored_hash {
                    println!("cargo:warning=Skipping unchanged templates (O(1) hash check)");
                    return;
                }
            }
        }

        let (templates, total_original) = load_all_templates(templates_dir);

        if templates.is_empty() {
            println!("cargo:warning=No templates found for compression");
            return;
        }

        compress_and_save_templates(&templates, total_original);

        // Save hash for O(1) skip detection on next build
        let _ = write_hash_file(&hash_path, &current_hash);
    }
}

/// Calculate combined hash of all template files
fn calculate_templates_hash(templates_dir: &Path) -> Option<String> {
    use sha2::{Digest, Sha256};

    let mut hasher = Sha256::new();
    let mut file_count = 0;

    if let Ok(files) = collect_template_files(templates_dir) {
        // Sort files for deterministic hashing
        let mut sorted_files = files;
        sorted_files.sort();

        for file in sorted_files {
            if let Ok(content) = fs::read(&file) {
                // Include filename in hash for renames
                hasher.update(file.to_string_lossy().as_bytes());
                hasher.update(&content);
                file_count += 1;
            }
        }
    }

    if file_count == 0 {
        return None;
    }

    Some(format!("{:x}", hasher.finalize()))
}

/// Validate templates directory exists (cognitive complexity ≤2)
fn validate_templates_directory(templates_dir: &Path) -> bool {
    if templates_dir.exists() {
        true
    } else {
        println!("cargo:warning=Templates directory not found, skipping compression");
        false
    }
}

/// Load all template files and return templates map with total size (cognitive complexity ≤6)
fn load_all_templates(templates_dir: &Path) -> (std::collections::HashMap<String, String>, usize) {
    use std::collections::HashMap;
    let mut templates = HashMap::new();
    let mut total_original = 0usize;

    if let Ok(entries) = collect_template_files(templates_dir) {
        for entry in entries {
            if let Some((name, content)) = read_template_file(&entry) {
                total_original += content.len();
                templates.insert(name, content);
            }
        }
    }

    (templates, total_original)
}

/// Compress templates and save to output file (cognitive complexity ≤8)
fn compress_and_save_templates(
    templates: &std::collections::HashMap<String, String>,
    total_original: usize,
) {
    let serialized = serde_json_to_string(templates);

    if let Some(compressed) = create_compressed_data(serialized.as_bytes()) {
        let total_compressed = compressed.len();
        let template_code = generate_template_output(&compressed, templates.len());

        write_compressed_templates_file(&template_code);
        print_compression_stats(templates.len(), total_original, total_compressed);
    }
}

/// Generate template output code (cognitive complexity ≤2)
fn generate_template_output(compressed: &[u8], template_count: usize) -> String {
    let compressed_hex = generate_hex_string(compressed);
    generate_template_code(&compressed_hex, template_count)
}

/// Write compressed templates to output file (cognitive complexity ≤2)
fn write_compressed_templates_file(template_code: &str) {
    let out_dir = env::var("OUT_DIR")
        .expect("OUT_DIR environment variable must be set by Cargo during build");
    let dest_path = Path::new(&out_dir).join("compressed_templates.rs");
    let _ = fs::write(dest_path, template_code);
}

/// Print compression statistics (cognitive complexity ≤3)
fn print_compression_stats(template_count: usize, total_original: usize, total_compressed: usize) {
    #[allow(clippy::cast_precision_loss)]
    let reduction_percent = (1.0 - total_compressed as f64 / total_original as f64) * 100.0;

    println!(
        "cargo:warning=Compressed {template_count} templates ({total_original} -> {total_compressed} bytes, {reduction_percent:.1}% reduction)"
    );
}

/// Collects template files from directory
///
/// # Errors
///
/// Returns error if directory cannot be read
fn collect_template_files(dir: &Path) -> Result<Vec<std::path::PathBuf>, std::io::Error> {
    let mut files = Vec::new();
    for entry in fs::read_dir(dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            files.extend(collect_template_files(&path)?);
        } else if path
            .extension()
            .is_some_and(|ext| ext == "hbs" || ext == "json")
        {
            files.push(path);
        }
    }
    Ok(files)
}

fn read_template_file(path: &Path) -> Option<(String, String)> {
    let name = path
        .strip_prefix("templates")
        .ok()?
        .to_string_lossy()
        .to_string();
    let content = fs::read_to_string(path).ok()?;
    Some((name, content))
}

fn serde_json_to_string<T: serde::Serialize>(value: &T) -> String {
    serde_json::to_string(value).unwrap_or_else(|_| "{}".to_string())
}

fn generate_hex_string(data: &[u8]) -> String {
    data.iter().fold(String::new(), |mut acc, b| {
        use std::fmt::Write;
        let _ = write!(acc, "{b:02x}");
        acc
    })
}

fn generate_template_code(hex: &str, count: usize) -> String {
    format!(
        r#"// Auto-generated compressed templates
use std::collections::HashMap;
use once_cell::sync::Lazy;

const COMPRESSED_TEMPLATES: &str = "{hex}";

pub static TEMPLATES: Lazy<HashMap<String, String>> = Lazy::new(|| {{
    use flate2::read::GzDecoder;
    use std::io::Read;
    
    let compressed = hex::decode(COMPRESSED_TEMPLATES).expect("Valid hex");
    let mut decoder = GzDecoder::new(&compressed[..]);
    let mut decompressed = String::new();
    decoder.read_to_string(&mut decompressed).expect("Decompression failed");
    
    serde_json::from_str(&decompressed).expect("Valid JSON")
}});

// Template count: {count}
"#
    )
}

fn minify_demo_assets() {
    println!("cargo:warning=Minifying demo assets...");

    let demo_dir = Path::new("../assets/demo");
    let output_dir = Path::new("assets/demo");
    let _ = fs::create_dir_all(output_dir);

    // Minify JavaScript
    minify_js_file(&demo_dir.join("app.js"), &output_dir.join("app.min.js"));

    // Minify CSS
    minify_css_file(
        &demo_dir.join("style.css"),
        &output_dir.join("style.min.css"),
    );

    // Copy other demo assets as-is
    copy_demo_asset(
        &demo_dir.join("favicon.ico"),
        &output_dir.join("favicon.ico"),
    );
}

fn minify_js_file(input_path: &Path, output_path: &Path) {
    if !input_path.exists() {
        println!(
            "cargo:warning=JavaScript file not found: {}",
            input_path.display()
        );
        return;
    }

    // O(1) optimization: Skip if unchanged
    let Some(file_name) = output_path.file_name() else {
        println!("cargo:warning=Invalid output path: no file name");
        return;
    };
    let hash_path = output_path.with_file_name(format!("{}.hash", file_name.to_string_lossy()));
    if output_path.exists() && !has_file_changed(input_path, &hash_path) {
        println!(
            "cargo:warning=Skipping unchanged JavaScript: {} (O(1) hash check)",
            input_path.display()
        );
        return;
    }

    let content = match fs::read_to_string(input_path) {
        Ok(content) => content,
        Err(e) => {
            println!("cargo:warning=Failed to read JS file: {e}");
            return;
        }
    };

    let minified = simple_js_minify(&content);

    if let Err(e) = fs::write(output_path, &minified) {
        println!("cargo:warning=Failed to write minified JS: {e}");
        return;
    }

    // Save hash for O(1) skip detection on next build
    if let Some(hash) = calculate_file_hash(input_path) {
        let _ = write_hash_file(&hash_path, &hash);
    }

    #[allow(clippy::cast_precision_loss)]
    let reduction = (1.0 - minified.len() as f64 / content.len() as f64) * 100.0;
    println!(
        "cargo:warning=Minified JavaScript: {} -> {} bytes ({:.1}% reduction)",
        content.len(),
        minified.len(),
        reduction
    );
}

fn minify_css_file(input_path: &Path, output_path: &Path) {
    if !input_path.exists() {
        println!("cargo:warning=CSS file not found: {}", input_path.display());
        return;
    }

    // O(1) optimization: Skip if unchanged
    let Some(file_name) = output_path.file_name() else {
        println!("cargo:warning=Invalid output path: no file name");
        return;
    };
    let hash_path = output_path.with_file_name(format!("{}.hash", file_name.to_string_lossy()));
    if output_path.exists() && !has_file_changed(input_path, &hash_path) {
        println!(
            "cargo:warning=Skipping unchanged CSS: {} (O(1) hash check)",
            input_path.display()
        );
        return;
    }

    let content = match fs::read_to_string(input_path) {
        Ok(content) => content,
        Err(e) => {
            println!("cargo:warning=Failed to read CSS file: {e}");
            return;
        }
    };

    let minified = simple_css_minify(&content);

    if let Err(e) = fs::write(output_path, &minified) {
        println!("cargo:warning=Failed to write minified CSS: {e}");
        return;
    }

    // Save hash for O(1) skip detection on next build
    if let Some(hash) = calculate_file_hash(input_path) {
        let _ = write_hash_file(&hash_path, &hash);
    }

    #[allow(clippy::cast_precision_loss)]
    let reduction = (1.0 - minified.len() as f64 / content.len() as f64) * 100.0;
    println!(
        "cargo:warning=Minified CSS: {} -> {} bytes ({:.1}% reduction)",
        content.len(),
        minified.len(),
        reduction
    );
}

fn copy_demo_asset(input_path: &Path, output_path: &Path) {
    if input_path.exists() {
        let _ = fs::copy(input_path, output_path);
    }
}

fn simple_js_minify(content: &str) -> String {
    content
        .lines()
        .map(str::trim)
        .filter(|line| !line.is_empty() && !line.starts_with("//"))
        .collect::<Vec<_>>()
        .join(" ")
        .replace("; ", ";")
        .replace(", ", ",")
        .replace(" = ", "=")
        .replace(" + ", "+")
        .replace(" { ", "{")
        .replace(" } ", "}")
        .replace("{ ", "{")
        .replace(" }", "}")
}

fn simple_css_minify(content: &str) -> String {
    content
        .lines()
        .map(|line| {
            let line = line.trim();
            // Remove CSS comments
            if line.starts_with("/*") && line.ends_with("*/") {
                ""
            } else {
                line
            }
        })
        .filter(|line| !line.is_empty())
        .collect::<Vec<_>>()
        .join("")
        .replace("; ", ";")
        .replace(": ", ":")
        .replace(", ", ",")
        .replace(" { ", "{")
        .replace(" } ", "}")
        .replace("{ ", "{")
        .replace(" }", "}")
}

fn calculate_asset_hash() -> String {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};

    let mut hasher = DefaultHasher::new();

    // Hash all asset files
    if let Ok(entries) = fs::read_dir("assets/vendor") {
        for entry in entries.filter_map(Result::ok) {
            if let Ok(content) = fs::read(entry.path()) {
                content.hash(&mut hasher);
            }
        }
    }

    // Also hash demo assets
    if let Ok(entries) = fs::read_dir("assets/demo") {
        for entry in entries.filter_map(Result::ok) {
            if let Ok(content) = fs::read(entry.path()) {
                content.hash(&mut hasher);
            }
        }
    }

    format!("{:x}", hasher.finish())
}

/// Calculate SHA256 hash of a file for change detection
fn calculate_file_hash(path: &Path) -> Option<String> {
    use sha2::{Digest, Sha256};

    let content = fs::read(path).ok()?;
    let mut hasher = Sha256::new();
    hasher.update(&content);
    Some(format!("{:x}", hasher.finalize()))
}

/// Read stored hash from .hash file
fn read_stored_hash(hash_path: &Path) -> Option<String> {
    fs::read_to_string(hash_path).ok().map(|s| s.trim().to_string())
}

/// Write hash to .hash file
fn write_hash_file(hash_path: &Path, hash: &str) -> bool {
    fs::write(hash_path, hash).is_ok()
}

/// Check if source file has changed by comparing hashes
fn has_file_changed(source_path: &Path, hash_path: &Path) -> bool {
    // If hash file doesn't exist, file has "changed" (needs processing)
    if !hash_path.exists() {
        return true;
    }

    // Calculate current hash
    let Some(current_hash) = calculate_file_hash(source_path) else {
        return true; // Can't read source, assume changed
    };

    // Compare with stored hash
    let Some(stored_hash) = read_stored_hash(hash_path) else {
        return true; // Can't read stored hash, assume changed
    };

    current_hash != stored_hash
}

/// Compiles Cap'n Proto schema for MCP server
/// DISABLED: Cap'n Proto removed (unused bloat dependency)
#[allow(dead_code)]
fn compile_capnp_schema() {
    // REMOVED: capnpc dependency eliminated (unused)
    // Reason: 0 references found in codebase, removing bloat
    println!("cargo:warning=Cap'n Proto schema compilation skipped (dependency removed)");
}

/// Generate MCP discovery optimization tables for <10ms initialization
fn generate_mcp_discovery_tables() {
    println!("cargo:warning=Generating MCP discovery optimization tables");

    let out_dir = env::var("OUT_DIR").expect("OUT_DIR must be set");

    // Generate tool registry
    generate_tool_registry(&out_dir);

    // Generate alias table
    generate_alias_table(&out_dir);

    // Generate trigram index
    generate_trigram_index(&out_dir);
}

/// Generate static PHF map of all MCP tools for zero-copy initialization
fn generate_tool_registry(out_dir: &str) {
    let dest_path = Path::new(out_dir).join("tool_registry.rs");

    // Tool definitions from the current MCP server
    let tools = vec![
        (
            "analyze_complexity",
            "Analyze code complexity metrics (cyclomatic, cognitive)",
            vec!["complexity", "analyze", "metrics"],
        ),
        (
            "analyze_satd",
            "Find self-admitted technical debt in comments",
            vec!["satd", "debt", "todo", "fixme"],
        ),
        (
            "analyze_dead_code",
            "Detect unused functions and variables",
            vec!["dead", "unused", "code"],
        ),
        (
            "analyze_dag",
            "Generate dependency graphs and visualizations",
            vec!["dependency", "graph", "dag", "architecture"],
        ),
        (
            "analyze_deep_context",
            "Generate comprehensive codebase context",
            vec!["context", "summary", "analysis"],
        ),
        (
            "analyze_big_o",
            "Analyze algorithmic complexity",
            vec!["big-o", "algorithm", "performance"],
        ),
        (
            "refactor.start",
            "Begin refactoring workflow",
            vec!["refactor", "start", "begin"],
        ),
        (
            "refactor.nextIteration",
            "Continue refactoring process",
            vec!["refactor", "next", "continue"],
        ),
        (
            "refactor.getState",
            "Get current refactoring state",
            vec!["refactor", "state", "status"],
        ),
        (
            "refactor.stop",
            "End refactoring workflow",
            vec!["refactor", "stop", "end"],
        ),
        (
            "quality_gate",
            "Run comprehensive quality analysis",
            vec!["quality", "gate", "check"],
        ),
        (
            "quality_proxy",
            "Intercept and validate code changes",
            vec!["quality", "proxy", "validate"],
        ),
        (
            "git_operation",
            "Execute git operations",
            vec!["git", "version", "control"],
        ),
        (
            "generate_context",
            "Generate AI-optimized context",
            vec!["generate", "context", "ai"],
        ),
        (
            "scaffold_project",
            "Create project scaffolding",
            vec!["scaffold", "create", "generate", "project"],
        ),
        // Sprint 31: TDG System MCP Tools
        (
            "tdg_system_diagnostics",
            "Get comprehensive TDG system diagnostics and health monitoring",
            vec!["tdg", "diagnostics", "health", "monitoring", "system"],
        ),
        (
            "tdg_storage_management",
            "Manage TDG storage operations (stats, cleanup, flush, migrate)",
            vec!["tdg", "storage", "management", "cleanup", "migrate"],
        ),
        (
            "tdg_analyze_with_storage",
            "Analyze files using transactional TDG storage with caching",
            vec!["tdg", "analyze", "storage", "transactional", "cache"],
        ),
        (
            "tdg_performance_metrics",
            "Get real-time TDG performance metrics and adaptive thresholds",
            vec!["tdg", "performance", "metrics", "adaptive", "thresholds"],
        ),
        (
            "tdg_configure_storage",
            "Configure and validate TDG storage backends",
            vec!["tdg", "configure", "storage", "backend", "sled", "rocksdb"],
        ),
        (
            "tdg_health_check",
            "Comprehensive TDG system health check with recommendations",
            vec!["tdg", "health", "check", "recommendations", "status"],
        ),
        // Phase 4: Organizational Intelligence Integration
        (
            "generate_defect_aware_prompt",
            "Generate context-aware AI prompts from organizational intelligence and defect patterns",
            vec!["prompt", "defect", "organizational", "intelligence", "oip", "ai"],
        ),
    ];

    let mut registry_code = String::from(
        "// Auto-generated tool registry for zero-copy MCP initialization\n\n\
         #[derive(Debug, Clone)]\n\
         pub struct ToolMeta {\n\
             pub name: &'static str,\n\
             pub description: &'static str,\n\
             pub keywords: &'static [&'static str],\n\
         }\n\n\
         pub static TOOL_REGISTRY: once_cell::sync::Lazy<std::collections::HashMap<&'static str, ToolMeta>> = once_cell::sync::Lazy::new(|| {\n\
             let mut m = std::collections::HashMap::new();\n"
    );

    for (name, desc, keywords) in &tools {
        registry_code.push_str(&format!(
            "    m.insert(\"{name}\", ToolMeta {{\n\
                 name: \"{name}\",\n\
                 description: \"{desc}\",\n\
                 keywords: &{keywords:?},\n\
             }});\n"
        ));
    }

    registry_code.push_str("    m\n});\n");

    if let Err(e) = fs::write(&dest_path, registry_code) {
        println!("cargo:warning=Failed to write tool registry: {e}");
    }
}

/// Generate alias dispatch table from empirical usage patterns
fn generate_alias_table(out_dir: &str) {
    let dest_path = Path::new(out_dir).join("alias_table.rs");

    let aliases = vec![
        (
            "analyze_complexity",
            vec![
                "complexity",
                "cyclomatic",
                "cognitive",
                "analyze code",
                "code complexity",
                "mccabe",
                "sonar",
                "analyze",
                "metrics",
            ],
        ),
        (
            "analyze_satd",
            vec![
                "debt",
                "technical debt",
                "todo",
                "fixme",
                "hack",
                "satd",
                "find debt",
                "find todo",
                "self admitted",
                "admitted debt",
            ],
        ),
        (
            "analyze_dag",
            vec![
                "dependency",
                "dependencies",
                "graph",
                "visualize",
                "diagram",
                "show dependencies",
                "dependency graph",
                "architecture",
                "dag",
            ],
        ),
        (
            "scaffold_project",
            vec![
                "scaffold",
                "create",
                "generate",
                "make",
                "new",
                "init",
                "create project",
                "generate project",
                "new project",
                "project template",
            ],
        ),
        (
            "generate_context",
            vec![
                "context",
                "summary",
                "generate context",
                "ai context",
                "codebase context",
                "analyze codebase",
                "understand code",
            ],
        ),
        (
            "quality_gate",
            vec![
                "quality",
                "check quality",
                "quality check",
                "gate",
                "validate",
                "quality analysis",
                "code quality",
                "standards",
            ],
        ),
        (
            "refactor.start",
            vec![
                "refactor",
                "refactoring",
                "start refactor",
                "begin refactor",
                "improve code",
                "clean code",
                "restructure",
            ],
        ),
        (
            "git_operation",
            vec![
                "git",
                "version control",
                "commit",
                "branch",
                "merge",
                "git command",
                "source control",
            ],
        ),
        // Sprint 31: TDG System MCP Tool Aliases
        (
            "tdg_system_diagnostics",
            vec![
                "tdg diagnostics",
                "system health",
                "tdg health",
                "monitoring",
                "system status",
                "tdg status",
                "diagnostics",
                "health check",
            ],
        ),
        (
            "tdg_storage_management",
            vec![
                "tdg storage",
                "storage stats",
                "cleanup storage",
                "storage cleanup",
                "flush storage",
                "migrate storage",
                "storage migrate",
                "tdg cache",
            ],
        ),
        (
            "tdg_analyze_with_storage",
            vec![
                "tdg analyze",
                "analyze tdg",
                "transactional analysis",
                "cached analysis",
                "storage analysis",
                "tdg file",
            ],
        ),
        (
            "tdg_performance_metrics",
            vec![
                "tdg performance",
                "performance metrics",
                "adaptive thresholds",
                "tdg metrics",
                "system performance",
                "threshold management",
            ],
        ),
        (
            "tdg_configure_storage",
            vec![
                "configure tdg",
                "storage config",
                "backend config",
                "tdg backend",
                "sled config",
                "rocksdb config",
                "storage backend",
            ],
        ),
        (
            "tdg_health_check",
            vec![
                "tdg health",
                "system health",
                "health status",
                "tdg check",
                "system check",
                "health recommendations",
            ],
        ),
        // Phase 4: Organizational Intelligence Integration
        (
            "generate_defect_aware_prompt",
            vec![
                "defect aware",
                "ai prompt",
                "organizational intelligence",
                "oip prompt",
                "context prompt",
                "defect patterns",
                "quality prompt",
                "intelligent prompt",
                "org intelligence",
                "prompt generation",
            ],
        ),
    ];

    let mut alias_code = String::from(
        "// Auto-generated alias table for MCP tool discovery\n\n\
         pub static ALIAS_TABLE: once_cell::sync::Lazy<std::collections::HashMap<&'static str, Vec<&'static str>>> = once_cell::sync::Lazy::new(|| {\n\
             let mut m = std::collections::HashMap::new();\n"
    );

    for (tool, tool_aliases) in &aliases {
        alias_code.push_str(&format!(
            "    m.insert(\"{tool}\", vec!{tool_aliases:?});\n"
        ));
    }

    alias_code.push_str("    m\n});\n");

    if let Err(e) = fs::write(&dest_path, alias_code) {
        println!("cargo:warning=Failed to write alias table: {e}");
    }
}

/// Generate trigram index for fuzzy matching
fn generate_trigram_index(out_dir: &str) {
    let dest_path = Path::new(out_dir).join("trigram_index.rs");

    let trigram_code = r#"// Auto-generated trigram index for fuzzy matching
pub struct TrigramIndex;

impl TrigramIndex {
    #[inline(always)]
    pub fn pack_trigram(s: &[u8]) -> u32 {
        if s.len() < 3 { return 0; }
        (s[0] as u32) | ((s[1] as u32) << 8) | ((s[2] as u32) << 16)
    }
    
    pub fn similarity_score(&self, query: &str, candidate: &str) -> f32 {
        let q_bytes = query.to_lowercase().into_bytes();
        let c_bytes = candidate.to_lowercase().into_bytes();
        
        if q_bytes.len() < 3 || c_bytes.len() < 3 {
            return 0.0;
        }
        
        // Collect query trigrams
        let mut q_trigrams = Vec::with_capacity(q_bytes.len().saturating_sub(2));
        for i in 0..q_bytes.len().saturating_sub(2) {
            q_trigrams.push(Self::pack_trigram(&q_bytes[i..i+3]));
        }
        
        // Collect candidate trigrams
        let mut c_trigrams = Vec::with_capacity(c_bytes.len().saturating_sub(2));
        for i in 0..c_bytes.len().saturating_sub(2) {
            c_trigrams.push(Self::pack_trigram(&c_bytes[i..i+3]));
        }
        
        // Count matches
        let mut matches = 0;
        for q_tri in &q_trigrams {
            if c_trigrams.contains(q_tri) {
                matches += 1;
            }
        }
        
        // Jaccard similarity coefficient
        let union_size = q_trigrams.len() + c_trigrams.len() - matches;
        if union_size == 0 { return 0.0; }
        
        matches as f32 / union_size as f32
    }
    
    pub fn find_best_match<'a>(&self, query: &str, candidates: &[(&'a str, &str)]) -> Option<(&'a str, f32)> {
        let mut best_match = ("", 0.0f32);
        
        for (name, description) in candidates {
            // Check both name and description
            let name_score = self.similarity_score(query, name);
            let desc_score = self.similarity_score(query, description) * 0.7; // Weight description lower
            let combined = name_score.max(desc_score);
            
            if combined > best_match.1 {
                best_match = (name, combined);
            }
        }
        
        if best_match.1 > 0.4 {  // Empirically determined threshold
            Some(best_match)
        } else {
            None
        }
    }
}
"#;

    if let Err(e) = fs::write(&dest_path, trigram_code) {
        println!("cargo:warning=Failed to write trigram index: {e}");
    }
}

/// Generate stub files for coverage builds to avoid compilation errors
fn generate_stub_files(out_dir: &str) {
    // Generate functional stub for tool_registry.rs with test data
    let tool_registry = r#"
// Functional tool registry for coverage builds
use std::collections::HashMap;

pub struct ToolMeta {
    pub name: &'static str,
    pub description: &'static str,
    pub keywords: &'static [&'static str],
}

pub static TOOL_REGISTRY: once_cell::sync::Lazy<HashMap<&'static str, ToolMeta>> =
    once_cell::sync::Lazy::new(|| {
        let mut m = HashMap::new();
        m.insert("analyze_complexity", ToolMeta {
            name: "analyze_complexity",
            description: "Analyze code complexity metrics (cyclomatic, cognitive)",
            keywords: &["complexity", "analyze", "metrics"],
        });
        m.insert("quality_gate", ToolMeta {
            name: "quality_gate",
            description: "Run comprehensive quality analysis",
            keywords: &["quality", "gate", "check"],
        });
        m.insert("scaffold_project", ToolMeta {
            name: "scaffold_project",
            description: "Create project scaffolding",
            keywords: &["scaffold", "create", "generate", "project"],
        });
        m.insert("analyze_satd", ToolMeta {
            name: "analyze_satd",
            description: "Find self-admitted technical debt in comments",
            keywords: &["satd", "debt", "todo", "fixme"],
        });
        m.insert("analyze_dag", ToolMeta {
            name: "analyze_dag",
            description: "Generate dependency graphs and visualizations",
            keywords: &["dependency", "graph", "dag", "architecture"],
        });
        m.insert("generate_context", ToolMeta {
            name: "generate_context",
            description: "Generate AI-optimized context",
            keywords: &["generate", "context", "ai"],
        });
        m.insert("refactor.start", ToolMeta {
            name: "refactor.start",
            description: "Begin refactoring workflow",
            keywords: &["refactor", "start", "begin"],
        });
        m.insert("git_operation", ToolMeta {
            name: "git_operation",
            description: "Execute git operations",
            keywords: &["git", "version", "control"],
        });
        m.insert("analyze_dead_code", ToolMeta {
            name: "analyze_dead_code",
            description: "Detect unused functions and variables",
            keywords: &["dead", "unused", "code"],
        });
        m.insert("analyze_big_o", ToolMeta {
            name: "analyze_big_o",
            description: "Analyze algorithmic complexity",
            keywords: &["big-o", "algorithm", "performance"],
        });
        m.insert("analyze_deep_context", ToolMeta {
            name: "analyze_deep_context",
            description: "Generate comprehensive codebase context",
            keywords: &["context", "summary", "analysis"],
        });
        m.insert("refactor.nextIteration", ToolMeta {
            name: "refactor.nextIteration",
            description: "Continue refactoring process",
            keywords: &["refactor", "next", "continue"],
        });
        m.insert("refactor.getState", ToolMeta {
            name: "refactor.getState",
            description: "Get current refactoring state",
            keywords: &["refactor", "state", "status"],
        });
        m.insert("refactor.stop", ToolMeta {
            name: "refactor.stop",
            description: "End refactoring workflow",
            keywords: &["refactor", "stop", "end"],
        });
        m.insert("quality_proxy", ToolMeta {
            name: "quality_proxy",
            description: "Intercept and validate code changes",
            keywords: &["quality", "proxy", "validate"],
        });
        m
    });
"#;

    let dest = Path::new(out_dir).join("tool_registry.rs");
    if let Err(e) = fs::write(&dest, tool_registry) {
        println!("cargo:warning=Failed to write tool registry stub: {e}");
    }

    // Generate functional stub for alias_table.rs with test data
    let alias_table = r#"
// Functional alias table for coverage builds
pub static ALIAS_TABLE: once_cell::sync::Lazy<std::collections::HashMap<&'static str, Vec<&'static str>>> =
    once_cell::sync::Lazy::new(|| {
        let mut m = std::collections::HashMap::new();
        m.insert("analyze_complexity", vec!["complexity", "analyze", "metrics", "complxity", "complx"]);
        m.insert("analyze_satd", vec!["debt", "technical debt", "todo", "fixme"]);
        m.insert("analyze_dag", vec!["dependency", "dependencies", "graph", "show dependencies", "dependency graph"]);
        m.insert("scaffold_project", vec!["scaffold", "create", "generate", "create project", "scafold"]);
        m.insert("generate_context", vec!["context", "generate context", "ai context"]);
        m.insert("quality_gate", vec!["quality", "check quality", "quality check", "qualit"]);
        m.insert("refactor.start", vec!["refactor", "start refactor", "refactr"]);
        m.insert("git_operation", vec!["git", "version control"]);
        m
    });
"#;

    let dest = Path::new(out_dir).join("alias_table.rs");
    if let Err(e) = fs::write(&dest, alias_table) {
        println!("cargo:warning=Failed to write alias table stub: {e}");
    }

    // Generate functional stub for trigram_index.rs with test functionality
    let trigram_index = r#"
// Functional trigram index for coverage builds
pub struct TrigramIndex;

impl TrigramIndex {
    #[inline(always)]
    pub fn pack_trigram(s: &[u8]) -> u32 {
        if s.len() < 3 { return 0; }
        (s[0] as u32) | ((s[1] as u32) << 8) | ((s[2] as u32) << 16)
    }

    pub fn similarity_score(&self, query: &str, candidate: &str) -> f32 {
        let q_bytes = query.to_lowercase().into_bytes();
        let c_bytes = candidate.to_lowercase().into_bytes();

        if q_bytes.len() < 3 || c_bytes.len() < 3 {
            return if query.to_lowercase() == candidate.to_lowercase() { 1.0 } else { 0.0 };
        }

        // Exact match check
        if query.to_lowercase() == candidate.to_lowercase() {
            return 1.0;
        }

        // Simple substring matching for tests
        if candidate.to_lowercase().contains(&query.to_lowercase()) {
            return 0.8;
        }

        // Collect query trigrams
        let mut q_trigrams = Vec::with_capacity(q_bytes.len().saturating_sub(2));
        for i in 0..q_bytes.len().saturating_sub(2) {
            q_trigrams.push(Self::pack_trigram(&q_bytes[i..i+3]));
        }

        // Collect candidate trigrams
        let mut c_trigrams = Vec::with_capacity(c_bytes.len().saturating_sub(2));
        for i in 0..c_bytes.len().saturating_sub(2) {
            c_trigrams.push(Self::pack_trigram(&c_bytes[i..i+3]));
        }

        // Count matches
        let mut matches = 0;
        for q_tri in &q_trigrams {
            if c_trigrams.contains(q_tri) {
                matches += 1;
            }
        }

        // Jaccard similarity coefficient
        let union_size = q_trigrams.len() + c_trigrams.len() - matches;
        if union_size == 0 { return 0.0; }

        matches as f32 / union_size as f32
    }

    pub fn find_best_match<'a>(&self, query: &str, candidates: &[(&'a str, &str)]) -> Option<(&'a str, f32)> {
        let mut best_match = ("", 0.0f32);

        for (name, description) in candidates {
            // Check both name and description
            let name_score = self.similarity_score(query, name);
            let desc_score = self.similarity_score(query, description) * 0.7; // Weight description lower
            let combined = name_score.max(desc_score);

            if combined > best_match.1 {
                best_match = (name, combined);
            }
        }

        if best_match.1 > 0.4 {  // Empirically determined threshold
            Some(best_match)
        } else {
            None
        }
    }
}
"#;

    let dest = Path::new(out_dir).join("trigram_index.rs");
    if let Err(e) = fs::write(&dest, trigram_index) {
        println!("cargo:warning=Failed to write trigram index stub: {e}");
    }
}
