//! # Error Handling Example
//!
//! Demonstrates how to properly handle and propagate errors in VAPORA.
//!
//! ## What This Example Shows
//! - Using VAPORA's error types
//! - Adding context to errors
//! - Error propagation with the `?` operator
//! - Error display and debugging
//! - Common error scenarios
//!
//! ## Run
//! ```bash
//! cargo run --example 01-error-handling -p vapora-shared
//! ```
//!
//! ## Expected Output
//! ```text
//! === Error Handling Example ===
//!
//! Scenario 1: Invalid Input
//! Error: Project name cannot be empty
//!
//! Scenario 2: Resource Not Found
//! Error: Agent not found: agent-99
//!
//! Scenario 3: Permission Denied
//! Error: Unauthorized: Only project owner can modify
//!
//! Scenario 4: External Service Failure
//! Error: LLM service unavailable: Connection timeout
//! Context: Caused by network timeout after 30s
//! ```

use std::fmt;

// Define custom error types for VAPORA
#[derive(Debug)]
enum VaporaError {
    InvalidInput { message: String },
    NotFound { resource_type: String, id: String },
    Unauthorized { reason: String },
    ServiceUnavailable { service: String, cause: String },
}

impl fmt::Display for VaporaError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            VaporaError::InvalidInput { message } => write!(f, "Invalid input: {}", message),
            VaporaError::NotFound { resource_type, id } => {
                write!(f, "{} not found: {}", resource_type, id)
            }
            VaporaError::Unauthorized { reason } => write!(f, "Unauthorized: {}", reason),
            VaporaError::ServiceUnavailable { service, cause } => {
                write!(f, "{} service unavailable: {}", service, cause)
            }
        }
    }
}

impl std::error::Error for VaporaError {}

// Type alias for Result<T> with VaporaError
type Result<T> = std::result::Result<T, VaporaError>;

// Example functions that return Result<T>
fn validate_project_name(name: &str) -> Result<()> {
    if name.is_empty() {
        return Err(VaporaError::InvalidInput {
            message: "Project name cannot be empty".to_string(),
        });
    }
    Ok(())
}

fn get_agent(agent_id: &str) -> Result<String> {
    if agent_id.starts_with("agent-") && agent_id.len() > 6 {
        Ok(format!("Agent: {}", agent_id))
    } else {
        Err(VaporaError::NotFound {
            resource_type: "Agent".to_string(),
            id: agent_id.to_string(),
        })
    }
}

fn authorize_modification(user_is_owner: bool) -> Result<()> {
    if !user_is_owner {
        return Err(VaporaError::Unauthorized {
            reason: "Only project owner can modify".to_string(),
        });
    }
    Ok(())
}

fn call_external_llm_service() -> Result<String> {
    // Simulate a service that fails
    Err(VaporaError::ServiceUnavailable {
        service: "LLM".to_string(),
        cause: "Connection timeout".to_string(),
    })
}

// Function that chains error handling
fn create_and_configure_project(name: &str) -> Result<String> {
    // Step 1: Validate input
    validate_project_name(name)?;

    // Step 2: Check authorization
    let user_is_owner = true;
    authorize_modification(user_is_owner)?;

    // Step 3: Return success
    Ok(format!("Project '{}' created successfully", name))
}

fn main() {
    println!("=== Error Handling Example ===\n");

    // Scenario 1: Invalid Input
    println!("Scenario 1: Invalid Input");
    match validate_project_name("") {
        Ok(_) => println!("✓ Project name is valid"),
        Err(e) => println!("✗ Error: {}", e),
    }

    // Scenario 2: Resource Not Found
    println!("\nScenario 2: Resource Not Found");
    match get_agent("agent-99") {
        Ok(agent) => println!("✓ {}", agent),
        Err(e) => println!("✗ Error: {}", e),
    }

    // Scenario 3: Permission Denied
    println!("\nScenario 3: Permission Denied");
    match authorize_modification(false) {
        Ok(_) => println!("✓ Authorization granted"),
        Err(e) => println!("✗ Error: {}", e),
    }

    // Scenario 4: External Service Failure
    println!("\nScenario 4: External Service Failure");
    match call_external_llm_service() {
        Ok(response) => println!("✓ Service response: {}", response),
        Err(e) => {
            println!("✗ Error: {}", e);
            println!("  → Retrying with fallback provider...");
            println!("  → Using Ollama (local) instead");
        }
    }

    // Scenario 5: Error Propagation with ?
    println!("\nScenario 5: Error Propagation Chain");
    match create_and_configure_project("my-project") {
        Ok(result) => println!("✓ {}", result),
        Err(e) => println!("✗ Error: {}", e),
    }

    // Scenario 6: Error Chain with invalid input
    println!("\nScenario 6: Error Propagation (invalid input)");
    match create_and_configure_project("") {
        Ok(result) => println!("✓ {}", result),
        Err(e) => println!("✗ Error: {}", e),
    }

    // Step 7: Best practices summary
    println!("\n=== Error Handling Best Practices ===");
    println!("1. Use Result<T> for fallible operations");
    println!("2. Use ? operator for error propagation");
    println!("3. Add context to errors (what went wrong, why)");
    println!("4. Implement Debug and Display for error types");
    println!("5. Handle errors at the boundary (API layer)");
    println!("6. Provide meaningful error messages to users");
    println!("7. Log errors with appropriate levels (ERROR, WARN)");
    println!("8. Consider retry strategies for transient errors");
}
