//! HTTP API for Episteme (StemeDB).
//!
//! This crate provides a RESTful HTTP API using axum and utoipa for OpenAPI documentation.
//!
//! # Architecture
//!
//! The API follows the standard axum pattern:
//! - **DTOs** (`dto.rs`) - JSON request/response types with hex-encoded binary data
//! - **Handlers** (`handlers/`) - Thin HTTP handlers that delegate to underlying engines
//! - **State** (`state.rs`) - Shared application state (Journal, Store, QueryEngine)
//! - **Router** (`router()`) - axum router with OpenAPI support via utoipa-axum
//!
//! # Write Path
//!
//! POST /v1/assert → DTO → Assertion → serialize → append to WAL → return hash
//!
//! # Read Path
//!
//! GET /v1/query → QueryParams → Query → QueryEngine → Lens (optional) → DTOs
//!
//! # Example
//!
//! ```ignore
//! use stemedb_api::{create_router, AppState};
//!
//! let state = AppState::new(write_journal, read_journal, store);
//! let app = create_router(state);
//!
//! axum::Server::bind(&addr).serve(app.into_make_service()).await?;
//! ```

pub mod dto;
pub mod error;
pub mod handlers;
pub mod hex;
pub mod middleware;
pub mod state;

use axum::{
    routing::{get, post},
    Router,
};
use tower_http::trace::TraceLayer;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;

pub use error::{ApiError, Result};
pub use middleware::{MeterLayer, MeterService};
pub use state::AppState;

// Re-export the path items for OpenAPI
use handlers::{
    admin::__path_decay_trust_ranks,
    assert::__path_create_assertion,
    audit::{__path_get_audit, __path_list_audits},
    concepts::{
        __path_create_alias, __path_delete_alias, __path_list_aliases, __path_parse_concept_path,
        __path_resolve_alias, __path_suggest_aliases,
    },
    constraints::__path_constraints_query,
    epoch::__path_create_epoch,
    escalation::{__path_list_escalations, __path_resolve_escalation},
    gold_standard::{
        __path_create_gold_standard, __path_list_gold_standards, __path_remove_gold_standard,
        __path_verify_agent,
    },
    health::__path_health_check,
    layered::__path_layered_query,
    meter::{__path_get_quota_status, __path_set_quota_limit},
    query::__path_query_assertions,
    skeptic::__path_skeptic_query,
    source::{__path_get_provenance, __path_store_source},
    supersede::__path_supersede,
    trace::__path_trace,
    vote::__path_create_vote,
};

/// OpenAPI documentation schema.
#[derive(OpenApi)]
#[openapi(
    paths(
        create_assertion,
        create_epoch,
        create_vote,
        query_assertions,
        skeptic_query,
        layered_query,
        constraints_query,
        health_check,
        list_audits,
        get_audit,
        trace,
        supersede,
        get_quota_status,
        set_quota_limit,
        store_source,
        get_provenance,
        decay_trust_ranks,
        list_escalations,
        resolve_escalation,
        create_gold_standard,
        list_gold_standards,
        remove_gold_standard,
        verify_agent,
        create_alias,
        resolve_alias,
        delete_alias,
        list_aliases,
        suggest_aliases,
        parse_concept_path,
    ),
    components(
        schemas(
            dto::CreateAssertionRequest,
            dto::CreateVoteRequest,
            dto::CreateEpochRequest,
            dto::QueryParams,
            dto::AssertionResponse,
            dto::QueryResponse,
            dto::CreateResponse,
            dto::ErrorResponse,
            dto::HealthResponse,
            dto::ObjectValueDto,
            dto::LifecycleDto,
            dto::SupersessionTypeDto,
            dto::LensDto,
            dto::SignatureDto,
            dto::AuditQueryParams,
            dto::QueryAuditResponse,
            dto::QueryAuditListResponse,
            dto::QueryParamsAuditDto,
            dto::ContributingAssertionDto,
            dto::TraceParams,
            dto::TraceResponse,
            dto::SupersedeRequest,
            dto::SupersedeResponse,
            dto::SkepticQueryParams,
            dto::SkepticResponse,
            dto::ResolutionStatusDto,
            dto::ClaimSummaryDto,
            dto::SourceSummaryDto,
            dto::AgentSummaryDto,
            dto::SourceClassDto,
            dto::TierResolutionDto,
            dto::LayeredQueryResponse,
            dto::ConstraintsQueryParams,
            dto::ConstraintsResponse,
            dto::ConstraintEntryDto,
            handlers::meter::QuotaStatusResponse,
            handlers::meter::SetQuotaLimitRequest,
            handlers::meter::SetQuotaLimitResponse,
            dto::StoreSourceRequest,
            dto::StoreSourceResponse,
            dto::ProvenanceResponse,
            dto::DecayTrustRanksRequest,
            dto::DecayTrustRanksResponse,
            dto::EscalationEventDto,
            dto::EscalationLevelDto,
            dto::EscalationListResponse,
            dto::CreateGoldStandardRequest,
            dto::CreateGoldStandardResponse,
            dto::GoldStandardDto,
            dto::GoldStandardListResponse,
            dto::VerifyAgentRequest,
            dto::VerificationResult,
            dto::CreateAliasRequest,
            dto::AliasResponse,
            dto::DeleteAliasRequest,
            dto::DeleteAliasResponse,
            dto::ResolveAliasParams,
            dto::ResolveAliasResponse,
            dto::ListAliasesParams,
            dto::ListAliasesResponse,
            dto::AliasMapping,
            dto::AliasOriginDto,
            dto::AliasSuggestion,
            dto::SuggestAliasesResponse,
            dto::ConceptPathInfo,
        )
    ),
    tags(
        (name = "assertions", description = "Create and manage assertions"),
        (name = "epochs", description = "Create and manage epochs (paradigms)"),
        (name = "votes", description = "Create votes on assertions"),
        (name = "query", description = "Query assertions with filters and lenses"),
        (name = "health", description = "Health check endpoint"),
        (name = "audit", description = "Query audit trail for incident investigation"),
        (name = "supersession", description = "Supersede assertions for error correction"),
        (name = "meter", description = "Economic throttling and quota management"),
        (name = "provenance", description = "Source document storage and retrieval"),
        (name = "admin", description = "Administrative operations for system maintenance"),
        (name = "concepts", description = "ConceptPath and alias management for cross-scheme resolution"),
    ),
    info(
        title = "Episteme (StemeDB) API",
        version = env!("CARGO_PKG_VERSION"),
        description = "HTTP API for the probabilistic knowledge graph",
        contact(
            name = "Episteme Project",
        )
    )
)]
struct ApiDoc;

/// Create the axum router with all routes and OpenAPI documentation.
///
/// This creates a router without economic throttling (The Meter).
/// For production use, prefer `create_router_with_meter`.
pub fn create_router(state: AppState) -> Router {
    // Build the API router
    let api_router = Router::new()
        .route("/v1/assert", post(handlers::create_assertion))
        .route("/v1/epoch", post(handlers::create_epoch))
        .route("/v1/vote", post(handlers::create_vote))
        .route("/v1/query", get(handlers::query_assertions))
        .route("/v1/skeptic", get(handlers::skeptic_query))
        .route("/v1/layered", get(handlers::layered_query))
        .route("/v1/constraints", get(handlers::constraints_query))
        .route("/v1/health", get(handlers::health_check))
        .route("/v1/audit/queries", get(handlers::list_audits))
        .route("/v1/audit/query/{id}", get(handlers::get_audit))
        .route("/v1/trace", get(handlers::trace))
        .route("/v1/supersede", post(handlers::supersede))
        .route("/v1/meter/quota", get(handlers::get_quota_status))
        .route("/v1/meter/quota/limit", post(handlers::set_quota_limit))
        .route("/v1/source", post(handlers::store_source))
        .route("/v1/provenance/{hash}", get(handlers::get_provenance))
        .route("/v1/admin/decay-trust-ranks", post(handlers::decay_trust_ranks))
        .route("/v1/admin/escalations", get(handlers::list_escalations))
        .route("/v1/admin/escalations/:id/resolve", post(handlers::resolve_escalation))
        .route("/v1/admin/gold-standards", post(handlers::create_gold_standard))
        .route("/v1/admin/gold-standards", get(handlers::list_gold_standards))
        .route(
            "/v1/admin/gold-standards/:subject/:predicate",
            axum::routing::delete(handlers::remove_gold_standard),
        )
        .route("/v1/admin/verify-agent", post(handlers::verify_agent))
        // Concept hierarchy and alias endpoints
        .route("/v1/concepts/alias", post(handlers::create_alias))
        .route("/v1/concepts/alias", axum::routing::delete(handlers::delete_alias))
        .route("/v1/concepts/resolve", get(handlers::resolve_alias))
        .route("/v1/concepts/aliases", get(handlers::list_aliases))
        .route("/v1/concepts/suggest", get(handlers::suggest_aliases))
        .route("/v1/concepts/parse", get(handlers::parse_concept_path))
        .with_state(state)
        .layer(TraceLayer::new_for_http());

    // Mount Swagger UI
    Router::new()
        .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
        .merge(api_router)
}

/// Create the axum router with economic throttling (The Meter) enabled.
///
/// This router enforces per-agent per-hour quotas based on operation costs:
/// - Assert: 10 tokens base + 1/KB payload
/// - Vote: 1 token base + 1/KB payload
/// - Query: 5 tokens base + 1 per lens + 1/KB payload
///
/// Agents must provide `X-Agent-Id` header (hex-encoded Ed25519 public key).
/// Quota status headers are returned on all responses:
/// - `X-Quota-Remaining`: Tokens left in current window
/// - `X-Quota-Limit`: Total tokens per hour
/// - `X-Quota-Reset`: Unix timestamp when window resets
pub fn create_router_with_meter(state: AppState) -> Router {
    use std::sync::Arc;

    // Create MeterLayer with the quota store from state
    let meter_layer = MeterLayer::new(Arc::clone(&state.quota_store));

    // Build the API router with metering
    let api_router = Router::new()
        .route("/v1/assert", post(handlers::create_assertion))
        .route("/v1/epoch", post(handlers::create_epoch))
        .route("/v1/vote", post(handlers::create_vote))
        .route("/v1/query", get(handlers::query_assertions))
        .route("/v1/skeptic", get(handlers::skeptic_query))
        .route("/v1/layered", get(handlers::layered_query))
        .route("/v1/constraints", get(handlers::constraints_query))
        .route("/v1/health", get(handlers::health_check))
        .route("/v1/audit/queries", get(handlers::list_audits))
        .route("/v1/audit/query/{id}", get(handlers::get_audit))
        .route("/v1/trace", get(handlers::trace))
        .route("/v1/supersede", post(handlers::supersede))
        .route("/v1/meter/quota", get(handlers::get_quota_status))
        .route("/v1/meter/quota/limit", post(handlers::set_quota_limit))
        .route("/v1/source", post(handlers::store_source))
        .route("/v1/provenance/{hash}", get(handlers::get_provenance))
        .route("/v1/admin/decay-trust-ranks", post(handlers::decay_trust_ranks))
        .route("/v1/admin/escalations", get(handlers::list_escalations))
        .route("/v1/admin/escalations/:id/resolve", post(handlers::resolve_escalation))
        .route("/v1/admin/gold-standards", post(handlers::create_gold_standard))
        .route("/v1/admin/gold-standards", get(handlers::list_gold_standards))
        .route(
            "/v1/admin/gold-standards/:subject/:predicate",
            axum::routing::delete(handlers::remove_gold_standard),
        )
        .route("/v1/admin/verify-agent", post(handlers::verify_agent))
        // Concept hierarchy and alias endpoints
        .route("/v1/concepts/alias", post(handlers::create_alias))
        .route("/v1/concepts/alias", axum::routing::delete(handlers::delete_alias))
        .route("/v1/concepts/resolve", get(handlers::resolve_alias))
        .route("/v1/concepts/aliases", get(handlers::list_aliases))
        .route("/v1/concepts/suggest", get(handlers::suggest_aliases))
        .route("/v1/concepts/parse", get(handlers::parse_concept_path))
        .with_state(state)
        .layer(meter_layer)
        .layer(TraceLayer::new_for_http());

    // Mount Swagger UI
    Router::new()
        .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
        .merge(api_router)
}
