//! Synor Compiler SDK Examples for Rust
//!
//! Demonstrates smart contract compilation and analysis:
//! - WASM contract compilation and optimization
//! - ABI extraction and encoding
//! - Contract analysis and security scanning
//! - Validation and verification

use std::env;
use synor_compiler::{
    CompilerConfig, CompileOptions, OptimizationLevel, StripOptions, SynorCompiler,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client
    let config = CompilerConfig {
        api_key: env::var("SYNOR_API_KEY").unwrap_or_else(|_| "your-api-key".to_string()),
        endpoint: "https://compiler.synor.io/v1".to_string(),
        timeout: 60000,
        retries: 3,
        debug: false,
        default_optimization_level: OptimizationLevel::Size,
        max_contract_size: 256 * 1024,
        use_wasm_opt: true,
        validate: true,
        extract_metadata: true,
        generate_abi: true,
    };

    let compiler = SynorCompiler::new(config)?;

    // Check service health
    let healthy = compiler.health_check().await?;
    println!("Service healthy: {}\n", healthy);

    // Run examples
    compile_contract_example(&compiler).await?;
    compilation_modes_example(&compiler).await?;
    abi_example(&compiler).await?;
    analysis_example(&compiler).await?;
    validation_example(&compiler).await?;
    security_example(&compiler).await?;

    compiler.close().await?;
    Ok(())
}

/// Create a minimal valid WASM module for testing.
fn create_minimal_wasm() -> Vec<u8> {
    vec![
        0x00, 0x61, 0x73, 0x6d, // Magic: \0asm
        0x01, 0x00, 0x00, 0x00, // Version: 1
        // Type section
        0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f,
        // Function section
        0x03, 0x02, 0x01, 0x00,
        // Export section
        0x07, 0x08, 0x01, 0x04, 0x61, 0x64, 0x64, 0x00, 0x00,
        // Code section
        0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b,
    ]
}

async fn compile_contract_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Contract Compilation ===");

    let wasm = create_minimal_wasm();

    let result = compiler
        .compile(
            &wasm,
            Some(CompileOptions {
                optimization_level: OptimizationLevel::Size,
                use_wasm_opt: true,
                validate: true,
                extract_metadata: true,
                generate_abi: true,
                strip_options: Some(StripOptions {
                    strip_debug: true,
                    strip_producers: true,
                    strip_names: true,
                    strip_custom: true,
                    strip_unused: true,
                    preserve_sections: vec![],
                }),
            }),
        )
        .await?;

    println!("Compilation result:");
    println!("  Contract ID: {}", result.contract_id);
    println!("  Code hash: {}", result.code_hash);
    println!("  Original size: {} bytes", result.original_size);
    println!("  Optimized size: {} bytes", result.optimized_size);
    println!("  Size reduction: {:.1}%", result.size_reduction);
    println!("  Estimated deploy gas: {}", result.estimated_deploy_gas);

    if let Some(metadata) = &result.metadata {
        println!("\nMetadata:");
        println!("  Name: {}", metadata.name);
        println!("  Version: {}", metadata.version);
        println!("  SDK Version: {}", metadata.sdk_version);
    }

    if let Some(abi) = &result.abi {
        println!("\nABI:");
        println!("  Functions: {}", abi.functions.as_ref().map_or(0, |f| f.len()));
        println!("  Events: {}", abi.events.as_ref().map_or(0, |e| e.len()));
        println!("  Errors: {}", abi.errors.as_ref().map_or(0, |e| e.len()));
    }

    println!();
    Ok(())
}

async fn compilation_modes_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Compilation Modes ===");

    let wasm = create_minimal_wasm();

    // Development mode: fast compilation, debugging support
    println!("Development mode:");
    let dev_result = compiler.contracts.compile_dev(&wasm).await?;
    println!("  Size: {} bytes", dev_result.optimized_size);
    println!("  Optimization: none");

    // Production mode: maximum optimization
    println!("\nProduction mode:");
    let prod_result = compiler.contracts.compile_production(&wasm).await?;
    println!("  Size: {} bytes", prod_result.optimized_size);
    println!("  Optimization: aggressive");
    println!(
        "  Size savings: {} bytes",
        dev_result.optimized_size - prod_result.optimized_size
    );

    // Custom optimization levels
    println!("\nOptimization levels:");
    let levels = [
        OptimizationLevel::None,
        OptimizationLevel::Basic,
        OptimizationLevel::Size,
        OptimizationLevel::Aggressive,
    ];

    for level in levels {
        let result = compiler
            .compile(
                &wasm,
                Some(CompileOptions {
                    optimization_level: level,
                    ..Default::default()
                }),
            )
            .await?;
        println!("  {:?}: {} bytes", level, result.optimized_size);
    }

    println!();
    Ok(())
}

async fn abi_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== ABI Operations ===");

    let wasm = create_minimal_wasm();

    // Extract ABI from WASM
    let abi = compiler.abi.extract(&wasm).await?;
    println!("Contract: {}", abi.name);
    println!("Version: {}", abi.version);

    // List functions
    if let Some(functions) = &abi.functions {
        if !functions.is_empty() {
            println!("\nFunctions:");
            for func in functions {
                let inputs = func
                    .inputs
                    .as_ref()
                    .map(|inputs| {
                        inputs
                            .iter()
                            .map(|i| format!("{}: {}", i.name, i.type_info.type_name))
                            .collect::<Vec<_>>()
                            .join(", ")
                    })
                    .unwrap_or_default();

                let outputs = func
                    .outputs
                    .as_ref()
                    .map(|outputs| {
                        outputs
                            .iter()
                            .map(|o| o.type_info.type_name.clone())
                            .collect::<Vec<_>>()
                            .join(", ")
                    })
                    .unwrap_or_else(|| "void".to_string());

                let mut modifiers = vec![];
                if func.view {
                    modifiers.push("view");
                }
                if func.payable {
                    modifiers.push("payable");
                }

                println!(
                    "  {}({}) -> {} {}",
                    func.name,
                    inputs,
                    outputs,
                    modifiers.join(" ")
                );
                println!("    Selector: {}", func.selector);
            }
        }
    }

    // List events
    if let Some(events) = &abi.events {
        if !events.is_empty() {
            println!("\nEvents:");
            for event in events {
                let params = event
                    .params
                    .as_ref()
                    .map(|params| {
                        params
                            .iter()
                            .map(|p| {
                                let indexed = if p.indexed { "indexed " } else { "" };
                                format!("{}{}: {}", indexed, p.name, p.type_info.type_name)
                            })
                            .collect::<Vec<_>>()
                            .join(", ")
                    })
                    .unwrap_or_default();

                println!("  {}({})", event.name, params);
                println!("    Topic: {}", event.topic);
            }
        }
    }

    // Encode a function call
    if let Some(functions) = &abi.functions {
        if let Some(func) = functions.first() {
            let encoded = compiler
                .abi
                .encode_call(func, &["arg1".to_string(), "arg2".to_string()])
                .await?;
            println!("\nEncoded call to {}: {}", func.name, encoded);

            // Decode a result
            let decoded = compiler.abi.decode_result(func, &encoded).await?;
            println!("Decoded result: {:?}", decoded);
        }
    }

    println!();
    Ok(())
}

async fn analysis_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Contract Analysis ===");

    let wasm = create_minimal_wasm();

    // Full analysis
    let analysis = compiler.analysis.analyze(&wasm).await?;

    // Size breakdown
    if let Some(breakdown) = &analysis.size_breakdown {
        println!("Size breakdown:");
        println!("  Code: {} bytes", breakdown.code);
        println!("  Data: {} bytes", breakdown.data);
        println!("  Functions: {} bytes", breakdown.functions);
        println!("  Memory: {} bytes", breakdown.memory);
        println!("  Exports: {} bytes", breakdown.exports);
        println!("  Imports: {} bytes", breakdown.imports);
        println!("  Total: {} bytes", breakdown.total);
    }

    // Function analysis
    if let Some(functions) = &analysis.functions {
        if !functions.is_empty() {
            println!("\nFunction analysis:");
            for func in functions.iter().take(5) {
                println!("  {}:", func.name);
                println!("    Size: {} bytes", func.size);
                println!("    Instructions: {}", func.instruction_count);
                println!("    Locals: {}", func.local_count);
                println!("    Exported: {}", func.exported);
                println!("    Estimated gas: {}", func.estimated_gas);
            }
        }
    }

    // Import analysis
    if let Some(imports) = &analysis.imports {
        if !imports.is_empty() {
            println!("\nImports:");
            for imp in imports {
                println!("  {}.{} ({})", imp.module, imp.name, imp.kind);
            }
        }
    }

    // Gas analysis
    if let Some(gas) = &analysis.gas_analysis {
        println!("\nGas analysis:");
        println!("  Deployment: {}", gas.deployment_gas);
        println!("  Memory init: {}", gas.memory_init_gas);
        println!("  Data section: {}", gas.data_section_gas);
    }

    // Extract metadata
    let metadata = compiler.analysis.extract_metadata(&wasm).await?;
    println!("\nContract metadata:");
    println!("  Name: {}", metadata.name);
    println!("  Version: {}", metadata.version);
    println!("  Build timestamp: {}", metadata.build_timestamp);

    // Estimate deployment gas
    let gas = compiler.analysis.estimate_deploy_gas(&wasm).await?;
    println!("\nEstimated deployment gas: {}", gas);

    println!();
    Ok(())
}

async fn validation_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Contract Validation ===");

    let wasm = create_minimal_wasm();

    // Full validation
    let result = compiler.validation.validate(&wasm).await?;
    println!("Valid: {}", result.valid);
    println!("Exports: {}", result.export_count);
    println!("Imports: {}", result.import_count);
    println!("Functions: {}", result.function_count);
    println!("Memory pages: {}", result.memory_pages);

    if let Some(errors) = &result.errors {
        if !errors.is_empty() {
            println!("\nValidation errors:");
            for error in errors {
                println!("  [{}] {}", error.code, error.message);
                if let Some(location) = &error.location {
                    println!("    at {}", location);
                }
            }
        }
    }

    if let Some(warnings) = &result.warnings {
        if !warnings.is_empty() {
            println!("\nWarnings:");
            for warning in warnings {
                println!("  {}", warning);
            }
        }
    }

    // Quick validation
    let is_valid = compiler.validation.is_valid(&wasm).await?;
    println!("\nQuick validation: {}", is_valid);

    // Get validation errors only
    let errors = compiler.validation.get_errors(&wasm).await?;
    println!("Error count: {}", errors.len());

    // Validate required exports
    let has_required = compiler
        .validation
        .validate_exports(&wasm, &["init", "execute", "query"])
        .await?;
    println!("Has required exports: {}", has_required);

    // Validate memory constraints
    let memory_valid = compiler.validation.validate_memory(&wasm, 16).await?;
    println!("Memory within 16 pages: {}", memory_valid);

    println!();
    Ok(())
}

async fn security_example(compiler: &SynorCompiler) -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Security Scanning ===");

    let wasm = create_minimal_wasm();

    let security = compiler.analysis.security_scan(&wasm).await?;

    println!("Security score: {}/100", security.score);

    if let Some(issues) = &security.issues {
        if !issues.is_empty() {
            println!("\nSecurity issues:");
            for issue in issues {
                let icon = match issue.severity.as_str() {
                    "critical" => "[CRIT]",
                    "high" => "[HIGH]",
                    "medium" => "[MED]",
                    "low" => "[LOW]",
                    _ => "[???]",
                };
                println!("{} [{}] {}", icon, issue.severity.to_uppercase(), issue.issue_type);
                println!("   {}", issue.description);
                if let Some(location) = &issue.location {
                    println!("   at {}", location);
                }
            }
        } else {
            println!("No security issues found!");
        }
    }

    if let Some(recommendations) = &security.recommendations {
        if !recommendations.is_empty() {
            println!("\nRecommendations:");
            for rec in recommendations {
                println!("  * {}", rec);
            }
        }
    }

    println!();
    Ok(())
}
