//! Handlers for write operations (assert, vote).

use axum::extract::State;
use axum::Json;
use std::sync::Arc;
use tracing::instrument;

use crate::gateway::service::GatewayState;

use super::types::{
    ApiError, AssertionResponse, CreateAssertionRequest, VoteRequest, VoteResponse,
};

/// POST /v1/assert - Create a new assertion.
#[instrument(skip(state, req), fields(subject = %req.subject))]
pub async fn handle_assert(
    State(state): State<Arc<GatewayState>>,
    Json(req): Json<CreateAssertionRequest>,
) -> Result<Json<AssertionResponse>, ApiError> {
    // 1. Route by subject hash
    let shard_id = state.router.route_subject(&req.subject).map_err(|e| ApiError {
        code: "UNAVAILABLE".to_string(),
        message: format!("Routing failed: {e}"),
    })?;

    // 2. Get leader for this shard
    let leader = state.router.get_leader(shard_id).map_err(|e| ApiError {
        code: "UNAVAILABLE".to_string(),
        message: format!("No leader for shard {shard_id}: {e}"),
    })?;

    // 3. Forward to leader via RPC (not yet wired)
    tracing::info!(
        shard_id = shard_id,
        leader = %leader.short_hex(),
        "Routed assertion to shard leader"
    );

    // Return routing result (actual RPC forwarding requires stemedb-rpc integration)
    Ok(Json(AssertionResponse {
        assertion_id: format!("pending_{}", req.subject),
        shard_id,
        leader_node: leader.short_hex(),
    }))
}

/// POST /v1/vote - Submit a vote.
#[instrument(skip(state, req), fields(subject = %req.subject))]
pub async fn handle_vote(
    State(state): State<Arc<GatewayState>>,
    Json(req): Json<VoteRequest>,
) -> Result<Json<VoteResponse>, ApiError> {
    // Route by subject hash
    let shard_id = state.router.route_subject(&req.subject).map_err(|e| ApiError {
        code: "UNAVAILABLE".to_string(),
        message: format!("Routing failed: {e}"),
    })?;

    // Get leader
    let leader = state.router.get_leader(shard_id).map_err(|e| ApiError {
        code: "UNAVAILABLE".to_string(),
        message: format!("No leader for shard {shard_id}: {e}"),
    })?;

    // Forward to leader via RPC (not yet wired)
    tracing::info!(
        shard_id = shard_id,
        leader = %leader.short_hex(),
        assertion_id = %req.assertion_id,
        "Routed vote to shard leader"
    );

    Ok(Json(VoteResponse { success: true, shard_id }))
}
