//! Example demonstrating the `IntoResponse` trait for ergonomic error handling
//!
//! This example shows how to use the blanket implementation of `IntoResponse`
//! for `Result<T, CoreError>` to automatically convert results to responses.

use ruxno::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    id: u32,
    name: String,
    email: String,
}

#[derive(Debug, Serialize)]
struct ApiResponse<T> {
    success: bool,
    data: Option<T>,
    message: String,
}

impl<T: Serialize> From<ApiResponse<T>> for Response {
    fn from(api_response: ApiResponse<T>) -> Self {
        Response::json(&api_response)
            .unwrap_or_else(|_| Response::text("Failed to serialize response").with_status(500))
    }
}

/// Simulates fetching a user from a database
fn fetch_user(id: u32) -> Result<User, RuxnoError> {
    if id == 1 {
        Ok(User {
            id: 1,
            name: "Alice".to_string(),
            email: "alice@example.com".to_string(),
        })
    } else if id == 0 {
        Err(RuxnoError::bad_request("User ID must be greater than 0"))
    } else {
        Err(RuxnoError::not_found(format!(
            "User with ID {} not found",
            id
        )))
    }
}

fn main() {
    println!("=== IntoResponse Trait Example ===\n");

    // Example 1: Successful result
    println!("Example 1: Fetching user with ID 1 (success)");
    let result: Result<ApiResponse<User>, RuxnoError> = fetch_user(1).map(|user| ApiResponse {
        success: true,
        data: Some(user),
        message: "User fetched successfully".to_string(),
    });

    let response = result.into_response();
    println!("Status: {}", response.status());
    println!("Response: {:?}\n", response);

    // Example 2: Validation error (400)
    println!("Example 2: Fetching user with ID 0 (validation error)");
    let result: Result<ApiResponse<User>, RuxnoError> = fetch_user(0).map(|user| ApiResponse {
        success: true,
        data: Some(user),
        message: "User fetched successfully".to_string(),
    });

    let response = result.into_response();
    println!("Status: {}", response.status());
    println!("Response: {:?}\n", response);

    // Example 3: Not found error (404)
    println!("Example 3: Fetching user with ID 999 (not found)");
    let result: Result<ApiResponse<User>, RuxnoError> = fetch_user(999).map(|user| ApiResponse {
        success: true,
        data: Some(user),
        message: "User fetched successfully".to_string(),
    });

    let response = result.into_response();
    println!("Status: {}", response.status());
    println!("Response: {:?}\n", response);

    // Example 4: Direct error conversion
    println!("Example 4: Direct error to response conversion");
    let error = RuxnoError::internal("Database connection failed");
    let response = error.into_response();
    println!("Status: {}", response.status());
    println!("Response: {:?}\n", response);

    println!("=== Benefits ===");
    println!("✅ No need to implement From<Result<T, Error>> for Response");
    println!("✅ Works around Rust's orphan rule");
    println!("✅ Ergonomic error handling with .into_response()");
    println!("✅ Blanket implementation for any Result<T, CoreError> where T: Into<Response>");
}
