// Proposals API endpoints for approval gates

use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use serde::Deserialize;
use vapora_shared::models::{Proposal, ProposalReview, ProposalStatus, RiskLevel};

use crate::api::state::AppState;
use crate::api::ApiResult;

#[derive(Debug, Deserialize)]
pub struct ProposalQueryParams {
    pub project_id: String,
    pub status: Option<String>,
    #[allow(dead_code)]
    pub risk_level: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct CreateProposalPayload {
    pub project_id: String,
    pub task_id: String,
    pub agent_id: String,
    pub title: String,
    pub description: Option<String>,
    pub risk_level: String,
    pub plan_details: serde_json::Value,
}

#[derive(Debug, Deserialize)]
pub struct AddReviewPayload {
    pub reviewer_id: String,
    pub feedback: String,
    pub approved: bool,
}

/// List proposals with optional filters
///
/// GET /api/v1/proposals?project_id=xxx&status=proposed
pub async fn list_proposals(
    State(state): State<AppState>,
    Query(params): Query<ProposalQueryParams>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let status = params.status.as_ref().map(|s| match s.as_str() {
        "proposed" => ProposalStatus::Proposed,
        "approved" => ProposalStatus::Approved,
        "rejected" => ProposalStatus::Rejected,
        "executed" => ProposalStatus::Executed,
        _ => ProposalStatus::Proposed,
    });

    let proposals = state
        .proposal_service
        .list_proposals(&params.project_id, tenant_id, status)
        .await?;

    Ok(Json(proposals))
}

/// Get a specific proposal
///
/// GET /api/v1/proposals/:id
pub async fn get_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let proposal = state.proposal_service.get_proposal(&id, tenant_id).await?;

    Ok(Json(proposal))
}

/// Create a new proposal
///
/// POST /api/v1/proposals
pub async fn create_proposal(
    State(state): State<AppState>,
    Json(payload): Json<CreateProposalPayload>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let risk_level = match payload.risk_level.as_str() {
        "low" => RiskLevel::Low,
        "medium" => RiskLevel::Medium,
        "high" => RiskLevel::High,
        _ => RiskLevel::Low,
    };

    let plan_details: vapora_shared::models::PlanDetails =
        serde_json::from_value(payload.plan_details).map_err(|_| {
            vapora_shared::VaporaError::InvalidInput("Invalid plan details".to_string())
        })?;

    let proposal = Proposal {
        id: None,
        tenant_id: tenant_id.to_string(),
        project_id: payload.project_id,
        task_id: payload.task_id,
        agent_id: payload.agent_id,
        title: payload.title,
        description: payload.description,
        status: ProposalStatus::Proposed,
        risk_level,
        plan_details,
        created_at: chrono::Utc::now(),
        submitted_at: None,
        reviewed_at: None,
        executed_at: None,
    };

    let created = state.proposal_service.create_proposal(proposal).await?;

    Ok((StatusCode::CREATED, Json(created)))
}

/// Update proposal
///
/// PUT /api/v1/proposals/:id
pub async fn update_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<Proposal>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let updated = state
        .proposal_service
        .update_proposal(&id, tenant_id, payload)
        .await?;

    Ok(Json(updated))
}

/// Delete proposal
///
/// DELETE /api/v1/proposals/:id
pub async fn delete_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    state
        .proposal_service
        .delete_proposal(&id, tenant_id)
        .await?;

    Ok(StatusCode::NO_CONTENT)
}

/// Submit proposal for approval
///
/// PUT /api/v1/proposals/:id/submit
pub async fn submit_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let proposal = state
        .proposal_service
        .submit_proposal(&id, tenant_id)
        .await?;

    Ok(Json(proposal))
}

/// Approve proposal
///
/// PUT /api/v1/proposals/:id/approve
pub async fn approve_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let proposal = state
        .proposal_service
        .approve_proposal(&id, tenant_id)
        .await?;

    Ok(Json(proposal))
}

/// Reject proposal
///
/// PUT /api/v1/proposals/:id/reject
pub async fn reject_proposal(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let proposal = state
        .proposal_service
        .reject_proposal(&id, tenant_id)
        .await?;

    Ok(Json(proposal))
}

/// Mark proposal as executed
///
/// PUT /api/v1/proposals/:id/executed
pub async fn mark_executed(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let tenant_id = "default";

    let proposal = state.proposal_service.mark_executed(&id, tenant_id).await?;

    Ok(Json(proposal))
}

/// List reviews for proposal
///
/// GET /api/v1/proposals/:id/reviews
pub async fn list_reviews(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    let reviews = state.proposal_service.list_reviews(&id).await?;

    Ok(Json(reviews))
}

/// Add review to proposal
///
/// POST /api/v1/proposals/:id/reviews
pub async fn add_review(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<AddReviewPayload>,
) -> ApiResult<impl IntoResponse> {
    let review = ProposalReview {
        id: None,
        proposal_id: id.clone(),
        reviewer_id: payload.reviewer_id,
        feedback: payload.feedback,
        approved: payload.approved,
        created_at: chrono::Utc::now(),
    };

    let created = state.proposal_service.add_review(&id, review).await?;

    Ok((StatusCode::CREATED, Json(created)))
}
