//! The guardrails policy evaluation engine.
//!
//! Provides the [`check_policy`] entry point that validates a SQL query
//! against a set of policy rules, returning a [`PolicyResult`] with
//! violations, warnings, and an audit trail.

use super::audit::create_audit_entry;
use super::policy::PolicyConfig;
use super::rules::RuleRegistry;
use super::types::{
    PolicyCategory, PolicyResult, PolicyViolation, ViolationDetail, ViolationSeverity,
};
use crate::explainer::engine::explain;
use crate::schema::types::SchemaDefinition;
use std::time::Instant;

/// Check a SQL query against policy rules.
///
/// This is the primary entry point for the M4 guardrails engine. It:
/// 1. Explains the query (via the M2 explainer)
/// 2. If invalid, returns a result with a "validation_failed" violation
/// 3. If valid, evaluates all registered guardrail rules
/// 4. Determines whether the query is allowed (no Error-severity violations)
/// 5. Creates an audit entry for compliance logging
///
/// # Example
///
/// ```rust,no_run
/// use altimate_core::guardrails::engine::check_policy;
/// use altimate_core::guardrails::policy::PolicyConfig;
/// use altimate_core::SchemaDefinition;
///
/// # async fn example() {
/// let schema = SchemaDefinition::from_yaml_file("schema.yaml").unwrap();
/// let policy = PolicyConfig::from_yaml("cost_control:\n  max_joins: 3\n").unwrap();
/// let result = check_policy("SELECT * FROM users", &schema, &policy).await;
/// println!("Allowed: {}", result.allowed);
/// # }
/// ```
pub async fn check_policy(
    sql: &str,
    schema: &SchemaDefinition,
    policy: &PolicyConfig,
) -> PolicyResult {
    let start = Instant::now();

    let explanation_result = explain(sql, schema).await;

    if !explanation_result.valid || explanation_result.explanation.is_none() {
        let elapsed = start.elapsed();
        let violation = PolicyViolation {
            rule: "validation_failed".to_string(),
            category: PolicyCategory::Custom,
            severity: ViolationSeverity::Error,
            message: "Query failed validation and cannot be checked against policies".to_string(),
            remediation: Some("Fix the validation errors before running policy checks".to_string()),
            detail: ViolationDetail::CustomRule {
                detail: "Query did not pass SQL validation".to_string(),
            },
        };

        let audit = create_audit_entry(sql, false, 1, 0, 0, elapsed.as_millis() as u64);

        return PolicyResult {
            allowed: false,
            violations: vec![violation],
            warnings: Vec::new(),
            policies_evaluated: 0,
            audit,
        };
    }

    let explanation = explanation_result
        .explanation
        .expect("explanation should be Some when valid");

    let registry = RuleRegistry::with_defaults();
    let (violations, warnings, rules_count) =
        registry.evaluate_all(sql, &explanation, schema, policy);

    let allowed = !violations
        .iter()
        .any(|v| v.severity == ViolationSeverity::Error);

    let elapsed = start.elapsed();
    let audit = create_audit_entry(
        sql,
        allowed,
        violations.len(),
        warnings.len(),
        rules_count,
        elapsed.as_millis() as u64,
    );

    PolicyResult {
        allowed,
        violations,
        warnings,
        policies_evaluated: rules_count,
        audit,
    }
}
