//! Handler for quota status endpoint.

use axum::{
    extract::{Query, State},
    Json,
};
use serde::{Deserialize, Serialize};
use stemedb_storage::QuotaStore;
use tracing::instrument;
use utoipa::{IntoParams, ToSchema};

use crate::{hex::decode_agent_id, state::AppState, Result};

/// Query parameters for quota status.
#[derive(Debug, Clone, Deserialize, IntoParams)]
pub struct QuotaStatusParams {
    /// Agent's Ed25519 public key (hex-encoded, 64 chars)
    pub agent_id: String,
}

/// Response containing quota status.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct QuotaStatusResponse {
    /// Agent's public key (hex-encoded)
    pub agent_id: String,

    /// Remaining tokens in current window
    pub remaining: u64,

    /// Total tokens allowed per hour
    pub limit: u64,

    /// Unix timestamp when this quota window resets
    pub reset_at: u64,

    /// Tokens already consumed in current window
    pub used: u64,

    /// Current window start timestamp
    pub window_start: u64,
}

/// Get quota status for an agent.
///
/// Returns the current quota status including remaining tokens,
/// limit, and reset time for the current hourly window.
#[utoipa::path(
    get,
    path = "/v1/meter/quota",
    params(QuotaStatusParams),
    responses(
        (status = 200, description = "Quota status retrieved", body = QuotaStatusResponse),
        (status = 400, description = "Invalid agent_id format"),
    ),
    tag = "meter"
)]
#[instrument(skip(state), fields(agent_id = %params.agent_id))]
pub async fn get_quota_status(
    State(state): State<AppState>,
    Query(params): Query<QuotaStatusParams>,
) -> Result<Json<QuotaStatusResponse>> {
    // Decode agent ID from hex
    let agent_id = decode_agent_id(&params.agent_id)?;

    // Get current timestamp
    let timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0);

    // Query quota status
    let quota_result = state.quota_store.get_quota_status(&agent_id, timestamp).await?;

    // Calculate window start (truncate to hour)
    let window_start = (timestamp / 3600) * 3600;
    let used = quota_result.limit.saturating_sub(quota_result.remaining);

    Ok(Json(QuotaStatusResponse {
        agent_id: params.agent_id,
        remaining: quota_result.remaining,
        limit: quota_result.limit,
        reset_at: quota_result.reset_at,
        used,
        window_start,
    }))
}

/// Set quota limit for an agent (admin operation).
///
/// This allows setting a custom quota limit for a specific agent.
/// Typically used to grant higher quotas to trusted agents or
/// lower quotas to rate-limited agents.
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct SetQuotaLimitRequest {
    /// Agent's Ed25519 public key (hex-encoded, 64 chars)
    pub agent_id: String,

    /// New quota limit (tokens per hour)
    pub limit: u64,
}

/// Response for set quota limit operation.
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct SetQuotaLimitResponse {
    /// Agent's public key (hex-encoded)
    pub agent_id: String,

    /// New quota limit that was set
    pub limit: u64,

    /// Status message
    pub status: String,
}

/// Set a custom quota limit for an agent.
#[utoipa::path(
    post,
    path = "/v1/meter/quota/limit",
    request_body = SetQuotaLimitRequest,
    responses(
        (status = 200, description = "Quota limit updated", body = SetQuotaLimitResponse),
        (status = 400, description = "Invalid request"),
    ),
    tag = "meter"
)]
#[instrument(skip(state), fields(agent_id = %req.agent_id, limit = req.limit))]
pub async fn set_quota_limit(
    State(state): State<AppState>,
    Json(req): Json<SetQuotaLimitRequest>,
) -> Result<Json<SetQuotaLimitResponse>> {
    // Decode agent ID from hex
    let agent_id = decode_agent_id(&req.agent_id)?;

    // Set the quota limit
    state.quota_store.set_quota_limit(&agent_id, req.limit).await?;

    Ok(Json(SetQuotaLimitResponse {
        agent_id: req.agent_id,
        limit: req.limit,
        status: "Quota limit updated".to_string(),
    }))
}
