// Actix-web middleware demo example
// Run with: cargo run --example middleware_actix_demo --features actix
//
// This example demonstrates the ApiResultLayer middleware that automatically
// injects trace_id into ApiResult responses.

#![cfg(feature = "actix")]

use actix_web::{App, HttpServer, Responder, get, post, web};
use anycms_core::actix::ApiResultLayer;
use anycms_core::{ApiResult, FieldError, ResultPagination};
use serde::{Deserialize, Serialize};

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

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

// Mock user data
async fn get_users() -> Vec<User> {
    vec![
        User {
            id: 1,
            name: "Alice".to_string(),
            email: "alice@example.com".to_string(),
        },
        User {
            id: 2,
            name: "Bob".to_string(),
            email: "bob@example.com".to_string(),
        },
        User {
            id: 3,
            name: "Charlie".to_string(),
            email: "charlie@example.com".to_string(),
        },
    ]
}

async fn get_user_by_id(id: u32) -> Option<User> {
    let users = get_users().await;
    users.into_iter().find(|u| u.id == id)
}

#[get("/")]
async fn index() -> ApiResult<()> {
    ApiResult::ok().with_message("Service is running")
}

#[get("/users")]
async fn list_users() -> impl Responder {
    let users = get_users().await;
    let pagination = ResultPagination::new(3, 1, 10);

    ApiResult::list(users)
        .with_pagination(pagination)
        .with_extra("total_count", serde_json::json!(3))
}

#[get("/users/{id}")]
async fn get_user(path: web::Path<u32>) -> impl Responder {
    let user_id = path.into_inner();

    match get_user_by_id(user_id).await {
        Some(user) => ApiResult::value(user),
        None => ApiResult::<User>::fail("User not found").with_code(404),
    }
}

#[post("/users")]
async fn create_user(user_data: web::Json<CreateUserRequest>) -> impl Responder {
    let new_user = User {
        id: 999,
        name: user_data.name.clone(),
        email: user_data.email.clone(),
    };

    ApiResult::value(new_user).with_extra("created_at", serde_json::json!("2024-01-01T00:00:00Z"))
}

#[get("/validate")]
async fn validate_demo() -> impl Responder {
    ApiResult::<()>::validation_errors(vec![
        FieldError::new("email", "Invalid email format"),
        FieldError::new("name", "Name cannot be empty"),
    ])
}

#[get("/error")]
async fn error_demo() -> ApiResult<()> {
    ApiResult::fail("Database connection timeout").with_code(500)
}

#[get("/custom-trace")]
async fn custom_trace_demo() -> ApiResult<()> {
    // Handler-set trace_id is preserved; middleware won't overwrite it
    ApiResult::ok()
        .with_message("This response has a manually set trace_id")
        .with_trace_id("manual-trace-abc123")
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    println!("Starting Actix-web middleware demo server...");
    println!();
    println!("ApiResultLayer middleware automatically injects traceId into responses.");
    println!();
    println!("Endpoints:");
    println!("  GET  /              - Basic success response");
    println!("  GET  /users         - User list with pagination");
    println!("  GET  /users/1       - Get single user (found)");
    println!("  GET  /users/999     - Get single user (not found)");
    println!("  POST /users         - Create user");
    println!("  GET  /validate      - Validation errors");
    println!("  GET  /error         - Internal server error");
    println!("  GET  /custom-trace  - Manually set trace_id (not overwritten)");
    println!();
    println!("Try:");
    println!("  curl http://localhost:8080/");
    println!("  curl http://localhost:8080/users");
    println!("  curl http://localhost:8080/users/1");
    println!("  curl http://localhost:8080/users/999");
    println!("  curl http://localhost:8080/validate");
    println!("  curl http://localhost:8080/error");
    println!("  curl http://localhost:8080/custom-trace");
    println!();
    println!("Pass a custom trace ID via header:");
    println!("  curl -H 'X-Request-ID: my-custom-id' http://localhost:8080/");
    println!("  curl -H 'X-Trace-ID: another-id' http://localhost:8080/users");

    HttpServer::new(|| {
        App::new()
            .wrap(ApiResultLayer::default())
            .service(index)
            .service(list_users)
            .service(get_user)
            .service(create_user)
            .service(validate_demo)
            .service(error_demo)
            .service(custom_trace_demo)
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await?;

    Ok(())
}
