use axum::{
    routing::get,
    Router,
    Json,
    extract::{State, Path, Query},
    response::{IntoResponse, Response},
    http::StatusCode,
};
use std::sync::Arc;
use crate::state::AppState;
use serde::Deserialize;
use serde_json::json;
use uuid::Uuid;
use workflow_context::traits::ContextStore;

pub fn create_router(state: Arc<AppState>) -> Router {
    Router::new()
        .route("/health", get(health_check))
        .route("/workflows/{id}/graph", get(get_workflow_graph))
        // Context Inspector APIs
        .route("/context/{req_id}/tree/{commit_hash}", get(get_context_tree))
        .route("/context/{req_id}/blob/{commit_hash}/{*path}", get(get_context_blob))
        .route("/context/{req_id}/diff/{from_commit}/{to_commit}", get(get_context_diff))
        .with_state(state)
}

async fn health_check(State(_state): State<Arc<AppState>>) -> Json<serde_json::Value> {
    Json(json!({
        "status": "ok",
        "service": "workflow-orchestrator"
    }))
}

async fn get_workflow_graph(
    State(state): State<Arc<AppState>>,
    Path(id): Path<Uuid>,
) -> Json<serde_json::Value> {
    if let Some(dag_arc) = state.workflows.get(&id) {
        let dag = dag_arc.lock().await;
        let dto = dag.to_dto();
        Json(serde_json::to_value(dto).unwrap_or_else(|e| json!({
            "error": format!("Serialization error: {}", e)
        })))
    } else {
        Json(json!({
            "error": "Workflow not found"
        }))
    }
}

#[derive(Deserialize)]
struct TreeQuery {
    path: Option<String>,
}

async fn get_context_tree(
    State(state): State<Arc<AppState>>,
    Path((req_id, commit_hash)): Path<(String, String)>,
    Query(query): Query<TreeQuery>,
) -> Json<serde_json::Value> {
    let path = query.path.unwrap_or_default();
    match state.vgcs.list_dir(&req_id, &commit_hash, &path) {
        Ok(entries) => Json(json!(entries)),
        Err(e) => Json(json!({ "error": e.to_string() })),
    }
}

async fn get_context_blob(
    State(state): State<Arc<AppState>>,
    Path((req_id, commit_hash, path)): Path<(String, String, String)>,
) -> Response {
    match state.vgcs.read_file(&req_id, &commit_hash, &path) {
        Ok(mut reader) => {
            let mut buffer = Vec::new();
            if let Err(e) = std::io::Read::read_to_end(&mut reader, &mut buffer) {
                return (StatusCode::INTERNAL_SERVER_ERROR, format!("Read error: {}", e)).into_response();
            }
            // Detect mime type or just return plain text/json
            // For now we assume text/json usually
            let content_type = if path.ends_with(".json") {
                "application/json"
            } else {
                "text/plain"
            };
            
            ([(axum::http::header::CONTENT_TYPE, content_type)], buffer).into_response()
        },
        Err(e) => (StatusCode::NOT_FOUND, format!("Error: {}", e)).into_response(),
    }
}

async fn get_context_diff(
    State(state): State<Arc<AppState>>,
    Path((req_id, from_commit, to_commit)): Path<(String, String, String)>,
) -> Json<serde_json::Value> {
    match state.vgcs.diff(&req_id, &from_commit, &to_commit) {
        Ok(changes) => Json(json!(changes)),
        Err(e) => Json(json!({ "error": e.to_string() })),
    }
}

