//! Hospital Helpers Web Server
//!
//! RESTful API server for medical information

use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::{IntoResponse, Json},
    routing::{get, post},
    Router,
};
use hh::{
    client::HHClient,
    diagnosis::{DiagnosisService, Symptom},
    medicine::{MedicineQuery, MedicineService},
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tower_http::cors::CorsLayer;
use tracing::{info, Level};
use tracing_subscriber;

/// Shared application state
#[derive(Clone)]
struct AppState {
    medicine_service: Arc<MedicineService>,
    diagnosis_service: Arc<DiagnosisService>,
}

/// Health check response
#[derive(Serialize)]
struct HealthResponse {
    status: String,
    version: String,
}

/// Error response
#[derive(Serialize)]
struct ErrorResponse {
    error: String,
}

impl IntoResponse for ErrorResponse {
    fn into_response(self) -> axum::response::Response {
        (StatusCode::INTERNAL_SERVER_ERROR, Json(self)).into_response()
    }
}

/// Query parameters for medicine search
#[derive(Deserialize)]
struct SearchParams {
    q: String,
    #[serde(default)]
    limit: Option<usize>,
}

/// Request body for symptom analysis
#[derive(Deserialize)]
struct AnalyzeRequest {
    symptoms: Vec<Symptom>,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize tracing
    tracing_subscriber::fmt()
        .with_max_level(Level::INFO)
        .init();

    info!("Starting Hospital Helpers server...");

    // Initialize services
    let client = HHClient::new();
    let medicine_service = Arc::new(MedicineService::new(client.clone()));
    let diagnosis_service = Arc::new(DiagnosisService::new(client));

    let state = AppState {
        medicine_service,
        diagnosis_service,
    };

    // Build router
    let app = Router::new()
        .route("/", get(root_handler))
        .route("/health", get(health_handler))
        .route("/api/v1/medicines/search", get(search_medicines))
        .route("/api/v1/medicines/:name", get(get_medicine_details))
        .route("/api/v1/diagnosis/analyze", post(analyze_symptoms))
        .route("/api/v1/diseases/:name", get(get_disease_info))
        .layer(CorsLayer::permissive())
        .with_state(state);

    // Start server
    let addr = "127.0.0.1:3000";
    info!("Server listening on http://{}", addr);
    
    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;

    Ok(())
}

/// Root handler
async fn root_handler() -> Json<serde_json::Value> {
    Json(serde_json::json!({
        "name": "Hospital Helpers API",
        "version": "0.1.0",
        "endpoints": {
            "health": "/health",
            "medicine_search": "/api/v1/medicines/search?q={query}",
            "medicine_details": "/api/v1/medicines/{name}",
            "symptom_analysis": "/api/v1/diagnosis/analyze",
            "disease_info": "/api/v1/diseases/{name}"
        }
    }))
}

/// Health check handler
async fn health_handler() -> Json<HealthResponse> {
    Json(HealthResponse {
        status: "healthy".to_string(),
        version: env!("CARGO_PKG_VERSION").to_string(),
    })
}

/// Search medicines handler
async fn search_medicines(
    State(state): State<AppState>,
    Query(params): Query<SearchParams>,
) -> Result<Json<serde_json::Value>, ErrorResponse> {
    let mut query = MedicineQuery::new(&params.q);
    if let Some(limit) = params.limit {
        query.limit = Some(limit);
    }

    let results = state
        .medicine_service
        .search(&query)
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    Ok(Json(serde_json::json!({
        "query": params.q,
        "count": results.len(),
        "results": results
    })))
}

/// Get medicine details handler
async fn get_medicine_details(
    State(state): State<AppState>,
    Path(name): Path<String>,
) -> Result<Json<serde_json::Value>, ErrorResponse> {
    let medicine = state
        .medicine_service
        .get_details(&name)
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    Ok(Json(serde_json::json!(medicine)))
}

/// Analyze symptoms handler
async fn analyze_symptoms(
    State(state): State<AppState>,
    Json(payload): Json<AnalyzeRequest>,
) -> Result<Json<serde_json::Value>, ErrorResponse> {
    let result = state
        .diagnosis_service
        .analyze_symptoms(&payload.symptoms)
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    Ok(Json(serde_json::json!(result)))
}

/// Get disease information handler
async fn get_disease_info(
    State(state): State<AppState>,
    Path(name): Path<String>,
) -> Result<Json<serde_json::Value>, ErrorResponse> {
    let disease = state
        .diagnosis_service
        .get_disease_info(&name)
        .await
        .map_err(|e| ErrorResponse {
            error: e.to_string(),
        })?;

    Ok(Json(serde_json::json!(disease)))
}
