//! Handler for skeptic (conflict analysis) queries.

use axum::{
    extract::{Query as AxumQuery, State},
    Json,
};
use tracing::instrument;

use crate::{
    dto::{ErrorResponse, SkepticQueryParams, SkepticResponse, SourceMetadataDto},
    error::Result,
    services::{make_source_warning, SourceStatusEnricher},
    state::AppState,
};

use stemedb_query::SkepticResolver;
use stemedb_storage::{
    GenericSourceRegistry, GenericTrustRankStore, GenericVoteStore, SourceRegistry,
};

/// Query for conflict analysis using SkepticLens.
///
/// This endpoint provides "Trust but Verify" analysis, showing all competing
/// claims for a subject+predicate instead of picking a single winner.
///
/// # Response
///
/// Returns a `SkepticResponse` with:
/// - `status`: Unanimous, Agreed, or Contested
/// - `conflict_score`: 0.0 (unanimous) to 1.0 (chaos)
/// - `claims`: All distinct claims ranked by support
///
/// # Example
///
/// ```ignore
/// GET /v1/skeptic?subject=Semaglutide&predicate=muscle_effect
///
/// {
///   "status": "Contested",
///   "conflict_score": 0.72,
///   "claims": [
///     { "value": {"type": "Text", "value": "Significant loss"}, "weight_share": 0.45 },
///     { "value": {"type": "Text", "value": "Minimal loss"}, "weight_share": 0.35 }
///   ]
/// }
/// ```
#[utoipa::path(
    get,
    path = "/v1/skeptic",
    params(SkepticQueryParams),
    responses(
        (status = 200, description = "Conflict analysis successful", body = SkepticResponse),
        (status = 404, description = "No assertions found for subject+predicate", body = ErrorResponse),
        (status = 400, description = "Invalid request", body = ErrorResponse),
        (status = 500, description = "Internal server error", body = ErrorResponse)
    ),
    tag = "query"
)]
#[instrument(skip(state), fields(subject = %params.subject, predicate = %params.predicate, include_source_metadata = params.include_source_metadata))]
pub async fn skeptic_query(
    State(state): State<AppState>,
    AxumQuery(params): AxumQuery<SkepticQueryParams>,
) -> Result<Json<SkepticResponse>> {
    // Create the resolver with vote and trust stores
    let vote_store = std::sync::Arc::new(GenericVoteStore::new(state.store.clone()));
    let trust_store = std::sync::Arc::new(GenericTrustRankStore::new(state.store.clone()));
    let resolver = SkepticResolver::new(state.store.clone(), vote_store, trust_store);

    // Execute the skeptic resolution
    let view = resolver.resolve(&params.subject, &params.predicate).await?;

    // Return 404 if no assertions found
    let view = view.ok_or_else(|| {
        crate::error::ApiError::NotFound(format!(
            "No assertions found for subject '{}' and predicate '{}'",
            params.subject, params.predicate
        ))
    })?;

    // Convert to response DTO
    let mut response: SkepticResponse = view.into();

    // Enrich with source metadata if requested
    if params.include_source_metadata {
        let source_registry = GenericSourceRegistry::new(state.store.clone());
        enrich_sources_with_metadata(&source_registry, &mut response).await;
    }

    // Enrich with source warnings (P3.2 Cascade Flagging)
    enrich_claims_with_warnings(&state, &mut response).await;

    Ok(Json(response))
}

/// Enrich SkepticResponse with source metadata from the registry.
async fn enrich_sources_with_metadata<S: stemedb_storage::KVStore + 'static>(
    registry: &GenericSourceRegistry<S>,
    response: &mut SkepticResponse,
) {
    for claim in &mut response.claims {
        // Try to lookup source metadata by hash
        if let Ok(hash_bytes) = hex::decode(&claim.source.source_hash) {
            if hash_bytes.len() == 32 {
                let mut hash = [0u8; 32];
                hash.copy_from_slice(&hash_bytes);
                if let Ok(Some(record)) = registry.get(&hash).await {
                    claim.source.source_metadata = Some(SourceMetadataDto::from(record));
                }
            }
        }
    }
}

/// Enrich SkepticResponse claims with source warnings (P3.2 Cascade Flagging).
///
/// Attaches warnings to claims that cite deprecated or quarantined sources.
async fn enrich_claims_with_warnings(
    state: &crate::state::AppState,
    response: &mut SkepticResponse,
) {
    // Collect unique source hashes
    let source_hashes: Vec<[u8; 32]> = response
        .claims
        .iter()
        .filter_map(|claim| {
            hex::decode(&claim.source.source_hash).ok().and_then(|bytes| {
                if bytes.len() == 32 {
                    let mut hash = [0u8; 32];
                    hash.copy_from_slice(&bytes);
                    Some(hash)
                } else {
                    None
                }
            })
        })
        .collect();

    // Batch lookup source statuses
    let enricher = SourceStatusEnricher::new(state.store.clone());
    let source_statuses = match enricher.batch_lookup(&source_hashes).await {
        Ok(statuses) => statuses,
        Err(_) => return, // Don't fail the response if enrichment fails
    };

    // Attach warnings to claims
    for claim in &mut response.claims {
        if let Ok(hash_bytes) = hex::decode(&claim.source.source_hash) {
            if hash_bytes.len() == 32 {
                let mut hash = [0u8; 32];
                hash.copy_from_slice(&hash_bytes);
                if let Some(record) = source_statuses.get(&hash) {
                    claim.source_warning = make_source_warning(record);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    // Integration tests would go here
    // For now, the unit tests in stemedb-query cover the core functionality
}
