//! Intelligence bindings: estimate_cost, complexity_score, check_equivalence,
//! correct, evaluate.

use crate::schema::Schema;
use pyo3::prelude::*;

/// Estimate bytes scanned and USD cost for a SQL query.
///
/// Internally runs `explain` to get plan steps, then feeds them to the cost
/// estimator. The `dialect` determines pricing model (BigQuery, Snowflake, etc.).
#[pyfunction]
#[pyo3(signature = (sql, schema, dialect="generic"))]
pub fn estimate_cost(
    py: Python<'_>,
    sql: &str,
    schema: &Schema,
    dialect: &str,
) -> PyResult<PyObject> {
    let start = std::time::Instant::now();
    let d = crate::convert::parse_dialect(dialect)?;
    let explanation =
        crate::runtime::runtime().block_on(altimate_core::explain(sql, &schema.inner));
    let steps = explanation
        .explanation
        .map(|e| e.plan_steps)
        .unwrap_or_default();
    let result = altimate_core::complexity::estimate_cost(&steps, &schema.inner, d);
    crate::sdk::timed_emit_with_dialect("estimateCost", dialect, start);
    crate::convert::to_py_result(py, &result)
}

/// Compute a multi-dimensional complexity score (0-100) for a SQL query.
///
/// Combines structural, semantic, and cost dimensions. Returns tier classification
/// (Trivial, Simple, Moderate, Complex, VeryComplex).
#[pyfunction]
pub fn complexity_score(py: Python<'_>, sql: &str, schema: &Schema) -> PyResult<PyObject> {
    let start = std::time::Instant::now();
    let explanation =
        crate::runtime::runtime().block_on(altimate_core::explain(sql, &schema.inner));
    let (steps, cost_signals) = match explanation.explanation {
        Some(e) => (e.plan_steps, e.cost_signals),
        None => {
            let empty_lineage = altimate_core::explainer::types::QueryLineage {
                tables: vec![],
                columns_read: vec![],
                columns_output: vec![],
                join_graph: vec![],
            };
            (
                vec![],
                altimate_core::explainer::cost::analyze_cost(&[], &empty_lineage),
            )
        }
    };
    let lint_result = altimate_core::linter::lint(sql, &schema.inner);
    let cost_est =
        altimate_core::complexity::estimate_cost(&steps, &schema.inner, schema.inner.dialect);
    let result = altimate_core::complexity::compute_complexity_v2(
        &steps,
        &cost_signals,
        &lint_result.findings,
        Some(&cost_est),
    );
    crate::sdk::timed_emit("complexityScore", start);
    crate::convert::to_py_result(py, &result)
}

/// Check two SQL queries for semantic equivalence.
#[pyfunction]
pub fn check_equivalence(
    py: Python<'_>,
    sql_a: &str,
    sql_b: &str,
    schema: &Schema,
) -> PyResult<PyObject> {
    let start = std::time::Instant::now();
    let result = crate::runtime::runtime().block_on(
        altimate_core::equivalence::engine::check_equivalence(sql_a, sql_b, &schema.inner),
    );
    crate::sdk::timed_emit("checkEquivalence", start);
    crate::convert::to_py_result(py, &result)
}

/// Iterative correction protocol: propose-verify-refine loop.
#[pyfunction]
pub fn correct(py: Python<'_>, sql: &str, schema: &Schema) -> PyResult<PyObject> {
    let start = std::time::Instant::now();
    let config = Default::default();
    let result = crate::runtime::runtime().block_on(altimate_core::correction::engine::correct(
        sql,
        &schema.inner,
        &config,
    ));
    crate::sdk::timed_emit("correct", start);
    crate::convert::to_py_result(py, &result)
}

/// SQL quality scoring and grading (A-F scale).
#[pyfunction]
pub fn evaluate(py: Python<'_>, sql: &str, schema: &Schema) -> PyResult<PyObject> {
    let start = std::time::Instant::now();
    let config = Default::default();
    let result = crate::runtime::runtime().block_on(
        altimate_core::observability::engine::evaluate(sql, &schema.inner, &config),
    );
    crate::sdk::timed_emit("evaluate", start);
    crate::convert::to_py_result(py, &result)
}
