//! SPA Navigation Testing API
//!
//! Provides HTTP endpoints to test SPA navigation without requiring a browser.
//! These endpoints test the routing engine directly and can be used with curl
//! for automation, CI/CD, and debugging.

use std::collections::HashMap;
use std::time::Instant;

use axum::{
    extract::Query,
    http::StatusCode,
    response::Json,
    routing::{get, post},
    Router,
};
use rustelo_core_lib::routing::{self, RouteComponent};
use serde::{Deserialize, Serialize};

/// Route resolution test response
#[derive(Debug, Serialize)]
pub struct RouteResolutionResponse {
    pub path: String,
    pub component: Option<String>,
    pub language: String,
    pub valid: bool,
    pub canonical_path: String,
    pub metadata: RouteMetadata,
    pub resolution_time_ms: f64,
}

/// Route metadata for testing
#[derive(Debug, Serialize)]
pub struct RouteMetadata {
    pub title_key: Option<String>,
    pub description_key: Option<String>,
    pub is_multilingual: bool,
    pub parameters: HashMap<String, String>,
}

/// Navigation transition request
#[derive(Debug, Deserialize)]
pub struct NavigationRequest {
    pub from: String,
    pub to: String,
    pub language: Option<String>,
}

/// Navigation transition response
#[derive(Debug, Serialize)]
pub struct NavigationResponse {
    pub from: String,
    pub to: String,
    pub transition: String,
    pub from_component: Option<String>,
    pub to_component: Option<String>,
    pub language: String,
    pub valid: bool,
    pub warnings: Vec<String>,
}

/// Route validation query parameters
#[derive(Debug, Deserialize)]
pub struct RouteQuery {
    pub path: String,
    pub language: Option<String>,
}

/// Benchmark query parameters
#[derive(Debug, Deserialize)]
pub struct BenchmarkQuery {
    pub path: String,
    pub iterations: Option<u32>,
}

/// Complete route validation response
#[derive(Debug, Serialize)]
pub struct ValidationResponse {
    pub total_routes: usize,
    pub valid_routes: usize,
    pub invalid_routes: usize,
    pub validation_time_ms: f64,
    pub details: Vec<RouteValidationDetail>,
}

/// Individual route validation detail
#[derive(Debug, Serialize)]
pub struct RouteValidationDetail {
    pub path: String,
    pub component: Option<String>,
    pub language: String,
    pub valid: bool,
    pub error: Option<String>,
}

/// Benchmark response
#[derive(Debug, Serialize)]
pub struct BenchmarkResponse {
    pub path: String,
    pub iterations: u32,
    pub total_time_ms: f64,
    pub avg_time_ms: f64,
    pub min_time_ms: f64,
    pub max_time_ms: f64,
    pub component: Option<String>,
    pub language: String,
}

/// Create navigation test API router
pub fn router() -> Router<()> {
    Router::new()
        .route("/resolve", get(resolve_route))
        .route("/navigate", post(test_navigation))
        .route("/validate-all", get(validate_all_routes))
        .route("/benchmark", get(benchmark_route))
        .route("/dashboard", get(navigation_dashboard))
}

/// Test route resolution
async fn resolve_route(
    Query(params): Query<RouteQuery>,
) -> Result<Json<RouteResolutionResponse>, StatusCode> {
    let start = Instant::now();
    let path = &params.path;

    // Use the actual routing engine to resolve the route
    let route_info = routing::engine::resolve_route(path);
    let resolution_time = start.elapsed().as_secs_f64() * 1000.0;

    let component_name = route_info.component.as_ref().map(component_to_string);

    // Extract metadata from the component
    let metadata = RouteMetadata {
        title_key: route_info
            .component
            .as_ref()
            .map(|c| c.title_key().to_string()),
        description_key: route_info
            .component
            .as_ref()
            .map(|c| c.description_key().to_string()),
        is_multilingual: false, // Default multilingual support
        parameters: route_info.parameters.clone(),
    };

    let response = RouteResolutionResponse {
        path: path.clone(),
        component: component_name,
        language: route_info.language.clone(),
        valid: route_info.component.is_some(),
        canonical_path: route_info.canonical_path.clone(),
        metadata,
        resolution_time_ms: resolution_time,
    };

    Ok(Json(response))
}

/// Test navigation transition between routes
async fn test_navigation(
    Json(request): Json<NavigationRequest>,
) -> Result<Json<NavigationResponse>, StatusCode> {
    let from_route = routing::engine::resolve_route(&request.from);
    let to_route = routing::engine::resolve_route(&request.to);

    let mut warnings = Vec::new();

    // Check for language consistency
    if from_route.language != to_route.language {
        warnings.push(format!(
            "Language change detected: {} -> {}",
            from_route.language, to_route.language
        ));
    }

    // Determine transition type
    let transition = match (&from_route.component, &to_route.component) {
        (Some(_), Some(_)) => "valid",
        (Some(_), None) => "to_not_found",
        (None, Some(_)) => "from_not_found",
        (None, None) => "both_not_found",
    }
    .to_string();

    let valid = to_route.component.is_some();

    let response = NavigationResponse {
        from: request.from,
        to: request.to,
        transition,
        from_component: from_route.component.as_ref().map(component_to_string),
        to_component: to_route.component.as_ref().map(component_to_string),
        language: request.language.unwrap_or(to_route.language),
        valid,
        warnings,
    };

    Ok(Json(response))
}

/// Validate all configured routes
async fn validate_all_routes() -> Result<Json<ValidationResponse>, StatusCode> {
    let start = Instant::now();

    // Get all configured routes from the routing system
    let routing_config = routing::config::get_routing_config();
    let mut details = Vec::new();
    let mut valid_count = 0;

    for route_config in &routing_config.routes {
        if !route_config.enabled {
            continue;
        }

        let route_info = routing::engine::resolve_route(&route_config.path);
        let valid = route_info.component.is_some();

        if valid {
            valid_count += 1;
        }

        let error = if !valid {
            Some("Route not found".to_string())
        } else {
            None
        };

        details.push(RouteValidationDetail {
            path: route_config.path.clone(),
            component: route_info.component.as_ref().map(component_to_string),
            language: route_info.language,
            valid,
            error,
        });
    }

    let validation_time = start.elapsed().as_secs_f64() * 1000.0;
    let total_routes = details.len();
    let invalid_count = total_routes - valid_count;

    let response = ValidationResponse {
        total_routes,
        valid_routes: valid_count,
        invalid_routes: invalid_count,
        validation_time_ms: validation_time,
        details,
    };

    Ok(Json(response))
}

/// Benchmark route resolution performance
async fn benchmark_route(
    Query(params): Query<BenchmarkQuery>,
) -> Result<Json<BenchmarkResponse>, StatusCode> {
    let path = &params.path;
    let iterations = params.iterations.unwrap_or(1000);

    let mut times = Vec::with_capacity(iterations as usize);
    let mut component = None;
    let mut language = String::new();

    // Run benchmark iterations
    for _ in 0..iterations {
        let start = Instant::now();
        let route_info = routing::engine::resolve_route(path);
        let elapsed = start.elapsed().as_secs_f64() * 1000.0;
        times.push(elapsed);

        // Store result from first iteration
        if component.is_none() {
            component = route_info.component.as_ref().map(component_to_string);
            language = route_info.language;
        }
    }

    let total_time: f64 = times.iter().sum();
    let avg_time = total_time / iterations as f64;
    let min_time = times.iter().cloned().fold(f64::INFINITY, f64::min);
    let max_time = times.iter().cloned().fold(0.0, f64::max);

    let response = BenchmarkResponse {
        path: path.clone(),
        iterations,
        total_time_ms: total_time,
        avg_time_ms: avg_time,
        min_time_ms: min_time,
        max_time_ms: max_time,
        component,
        language,
    };

    Ok(Json(response))
}

/// Generate HTML dashboard for navigation testing
async fn navigation_dashboard() -> Result<String, StatusCode> {
    // Get route validation data
    let routing_config = routing::config::get_routing_config();
    let mut route_details = Vec::new();

    for route_config in &routing_config.routes {
        if !route_config.enabled {
            continue;
        }

        let route_info = routing::engine::resolve_route(&route_config.path);
        let valid = route_info.component.is_some();

        route_details.push((
            route_config.path.clone(),
            route_info.component.as_ref().map(component_to_string),
            route_info.language,
            valid,
        ));
    }

    // Generate HTML dashboard
    let html = generate_dashboard_html(&route_details);
    Ok(html)
}

/// Convert RouteComponent to string representation
fn component_to_string(component: &RouteComponent) -> String {
    component.as_str().to_string()
}

/// Generate HTML dashboard content
fn generate_dashboard_html(routes: &[(String, Option<String>, String, bool)]) -> String {
    let valid_count = routes.iter().filter(|(_, _, _, valid)| *valid).count();
    let total_count = routes.len();
    let invalid_count = total_count - valid_count;

    let route_rows: String = routes
        .iter()
        .map(|(path, component, language, valid)| {
            let status = if *valid { "✅" } else { "❌" };
            let component_name = component.as_deref().unwrap_or("None");
            format!(
                "<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td>{}</td></tr>",
                status,
                path,
                component_name,
                language,
                if *valid { "Valid" } else { "Invalid" }
            )
        })
        .collect();

    format!(
        r#"<!DOCTYPE html>
<html>
<head>
    <title>SPA Navigation Test Dashboard</title>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 20px; }}
        .summary {{ background: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; }}
        .valid {{ color: green; }}
        .invalid {{ color: red; }}
        table {{ width: 100%; border-collapse: collapse; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <h1>🧭 SPA Navigation Test Dashboard</h1>

    <div class="summary">
        <h2>Summary</h2>
        <p>Total Routes: <strong>{}</strong></p>
        <p class="valid">Valid Routes: <strong>{}</strong></p>
        <p class="invalid">Invalid Routes: <strong>{}</strong></p>
        <p>Success Rate: <strong>{:.1}%</strong></p>
    </div>

    <h2>Route Details</h2>
    <table>
        <thead>
            <tr>
                <th>Status</th>
                <th>Path</th>
                <th>Component</th>
                <th>Language</th>
                <th>Validation</th>
            </tr>
        </thead>
        <tbody>
            {}
        </tbody>
    </table>

    <div style="margin-top: 30px;">
        <h2>API Endpoints</h2>
        <ul>
            <li><code>GET /api/nav-test/resolve?path=/your-path</code></li>
            <li><code>POST /api/nav-test/navigate</code></li>
            <li><code>GET /api/nav-test/validate-all</code></li>
            <li><code>GET /api/nav-test/benchmark?path=/your-path</code></li>
        </ul>
    </div>
</body>
</html>"#,
        total_count,
        valid_count,
        invalid_count,
        (valid_count as f64 / total_count as f64) * 100.0,
        route_rows
    )
}
