use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    routing::{get, post},
    Json, Router,
};

use crate::types::*;
use crate::AppState;

pub(crate) fn router() -> Router<AppState> {
    Router::new()
        .route("/api/v1/intents", post(create_intent).get(list_intents))
        .route(
            "/api/v1/intents/:id",
            get(get_intent).put(update_intent).delete(delete_intent),
        )
        .route(
            "/api/v1/intents/:id/claim",
            post(claim_intent),
        )
        .route(
            "/api/v1/intents/:id/release",
            post(release_intent),
        )
        .route(
            "/api/v1/intents/:id/complete",
            post(complete_intent),
        )
}

#[derive(Debug, serde::Deserialize)]
struct ListIntentsQuery {
    project_id: Option<String>,
    node_id: Option<String>,
    status: Option<String>,
}

#[derive(Debug, serde::Deserialize)]
struct WorkerRequest {
    worker: String,
}

async fn create_intent(
    State(state): State<AppState>,
    Json(payload): Json<CreateIntentRequest>,
) -> (StatusCode, Json<ApiResponse<ExplorationIntent>>) {
    let intent = match state.db.create_intent(
        payload.project_id,
        &payload.node_id,
        &payload.direction,
        payload.description.as_deref(),
    ) {
        Ok(intent) => intent,
        Err(err) => return crate::db_error_response("intents.create_intent", "intent", err),
    };
    let _ = state.tx.send(format!("intent_created:{}", payload.project_id));
    (StatusCode::CREATED, Json(ApiResponse::ok(intent)))
}

async fn list_intents(
    State(state): State<AppState>,
    Query(query): Query<ListIntentsQuery>,
) -> Result<Json<ApiResponse<Vec<ExplorationIntent>>>, StatusCode> {
    let project_id = match &query.project_id {
        Some(pid) => match crate::resolve_project_id(&state.db, pid).await {
            Ok(p) => p,
            Err(_) => {
                return Ok(Json(ApiResponse::err("invalid project_id")));
            }
        },
        None => {
            return Ok(Json(ApiResponse::err("project_id is required")));
        }
    };

    let intents = state
        .db
        .list_intents(project_id, query.node_id.as_deref(), query.status.as_deref())
        .map_err(|err| crate::db_error_status("intents.list_intents", "intent", err))?;

    Ok(Json(ApiResponse::ok(intents)))
}

async fn get_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> Result<Json<ApiResponse<ExplorationIntent>>, StatusCode> {
    let intent = state
        .db
        .get_intent(&id)
        .map_err(|err| crate::db_error_status("intents.get_intent", "intent", err))?;

    match intent {
        Some(intent) => Ok(Json(ApiResponse::ok(intent))),
        None => {
            let _err = crate::AppError::new(
                StatusCode::NOT_FOUND,
                "intents.not_found",
                "intents.get_intent",
                "Intent not found.",
                "意图未找到。",
            );
            Err(crate::db_error_status("intents.get_intent", "intent", 
                rusqlite::Error::QueryReturnedNoRows))
        }
    }
}

async fn update_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<UpdateIntentRequest>,
) -> Result<(StatusCode, Json<ApiResponse<ExplorationIntent>>), StatusCode> {
    // First check if intent exists
    let existing = state
        .db
        .get_intent(&id)
        .map_err(|err| crate::db_error_status("intents.update_intent", "intent", err))?;

    let existing = match existing {
        Some(e) => e,
        None => {
            return Ok((
                StatusCode::NOT_FOUND,
                Json(ApiResponse::err(format!("Intent not found: {id}"))),
            ));
        }
    };

    let new_status = payload.status.as_ref().map(|s| s.as_str()).unwrap_or(existing.status.as_str());
    let new_worker = payload.description.as_ref().map(|_| existing.worker.as_deref()).unwrap_or(existing.worker.as_deref());

    let intent = state
        .db
        .update_intent_status(&id, new_status, new_worker)
        .map_err(|err| crate::db_error_status("intents.update_intent", "intent", err))?;

    let _ = state.tx.send(format!("intent_updated:{}", intent.project_id));
    Ok((StatusCode::OK, Json(ApiResponse::ok(intent))))
}

async fn delete_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> Result<Json<ApiResponse<()>>, StatusCode> {
    // Get project_id before deleting for broadcast
    let project_id = state
        .db
        .get_intent(&id)
        .map_err(|err| crate::db_error_status("intents.delete_intent", "intent", err))?
        .map(|i| i.project_id);

    let deleted = state
        .db
        .delete_intent(&id)
        .map_err(|err| crate::db_error_status("intents.delete_intent", "intent", err))?;

    if !deleted {
        return Err(StatusCode::NOT_FOUND);
    }

    if let Some(pid) = project_id {
        let _ = state.tx.send(format!("intent_deleted:{pid}"));
    }
    Ok(Json(ApiResponse::ok(())))
}

async fn claim_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<WorkerRequest>,
) -> Result<(StatusCode, Json<ApiResponse<ExplorationIntent>>), StatusCode> {
    let intent = state
        .db
        .claim_intent(&id, &payload.worker)
        .map_err(|err| crate::db_error_status("intents.claim_intent", "intent", err))?;

    let _ = state.tx.send(format!("intent_claimed:{}", intent.project_id));
    Ok((StatusCode::OK, Json(ApiResponse::ok(intent))))
}

async fn release_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> Result<(StatusCode, Json<ApiResponse<ExplorationIntent>>), StatusCode> {
    let intent = state
        .db
        .update_intent_status(&id, "open", None)
        .map_err(|err| crate::db_error_status("intents.release_intent", "intent", err))?;

    let _ = state.tx.send(format!("intent_released:{}", intent.project_id));
    Ok((StatusCode::OK, Json(ApiResponse::ok(intent))))
}

async fn complete_intent(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> Result<(StatusCode, Json<ApiResponse<ExplorationIntent>>), StatusCode> {
    let intent = state
        .db
        .complete_intent(&id)
        .map_err(|err| crate::db_error_status("intents.complete_intent", "intent", err))?;

    let _ = state.tx.send(format!("intent_completed:{}", intent.project_id));
    Ok((StatusCode::OK, Json(ApiResponse::ok(intent))))
}
