//! Serde JSON bridge: converts Rust types to Python objects via serde_json::Value.

use altimate_core::schema::types::SqlDialect;
use pyo3::prelude::*;
use pyo3::types::{PyBool, PyDict, PyFloat, PyList, PyString};
use serde_json::Value;

/// Convert a serde_json::Value to a Python object.
pub fn value_to_py(py: Python<'_>, val: &Value) -> PyResult<PyObject> {
    match val {
        Value::Null => Ok(py.None()),
        Value::Bool(b) => Ok(PyBool::new(py, *b).to_owned().into_any().unbind()),
        Value::Number(n) => {
            if let Some(i) = n.as_i64() {
                Ok(i.into_pyobject(py)?.into_any().unbind())
            } else if let Some(f) = n.as_f64() {
                Ok(PyFloat::new(py, f).into_any().unbind())
            } else {
                Ok(py.None())
            }
        }
        Value::String(s) => Ok(PyString::new(py, s).into_any().unbind()),
        Value::Array(arr) => {
            let items: Vec<PyObject> = arr
                .iter()
                .map(|v| value_to_py(py, v))
                .collect::<PyResult<_>>()?;
            Ok(PyList::new(py, &items)?.into_any().unbind())
        }
        Value::Object(map) => {
            let dict = PyDict::new(py);
            for (k, v) in map {
                dict.set_item(k, value_to_py(py, v)?)?;
            }
            Ok(dict.into_any().unbind())
        }
    }
}

/// Serialize any `Serialize` type to a Python dict/list/primitive.
pub fn to_py_result<T: serde::Serialize>(py: Python<'_>, val: &T) -> PyResult<PyObject> {
    let json_val = serde_json::to_value(val).map_err(|e| {
        pyo3::exceptions::PyRuntimeError::new_err(format!("serialization error: {e}"))
    })?;
    value_to_py(py, &json_val)
}

/// Parse a dialect string into SqlDialect (case-insensitive).
pub fn parse_dialect(s: &str) -> PyResult<SqlDialect> {
    match s.to_lowercase().as_str() {
        "generic" => Ok(SqlDialect::Generic),
        "snowflake" => Ok(SqlDialect::Snowflake),
        "postgres" | "postgresql" => Ok(SqlDialect::Postgres),
        "bigquery" => Ok(SqlDialect::BigQuery),
        "databricks" => Ok(SqlDialect::Databricks),
        "duckdb" => Ok(SqlDialect::DuckDB),
        "athena" => Ok(SqlDialect::Athena),
        "clickhouse" => Ok(SqlDialect::ClickHouse),
        "cockroachdb" => Ok(SqlDialect::CockroachDB),
        "datafusion" => Ok(SqlDialect::DataFusion),
        "doris" => Ok(SqlDialect::Doris),
        "dremio" => Ok(SqlDialect::Dremio),
        "drill" => Ok(SqlDialect::Drill),
        "druid" => Ok(SqlDialect::Druid),
        "dune" => Ok(SqlDialect::Dune),
        "exasol" => Ok(SqlDialect::Exasol),
        "fabric" => Ok(SqlDialect::Fabric),
        "hive" => Ok(SqlDialect::Hive),
        "materialize" => Ok(SqlDialect::Materialize),
        "mysql" => Ok(SqlDialect::MySQL),
        "oracle" => Ok(SqlDialect::Oracle),
        "presto" => Ok(SqlDialect::Presto),
        "redshift" => Ok(SqlDialect::Redshift),
        "risingwave" => Ok(SqlDialect::RisingWave),
        "singlestore" => Ok(SqlDialect::SingleStore),
        "solr" => Ok(SqlDialect::Solr),
        "spark" => Ok(SqlDialect::Spark),
        "sqlite" => Ok(SqlDialect::SQLite),
        "starrocks" => Ok(SqlDialect::StarRocks),
        "tableau" => Ok(SqlDialect::Tableau),
        "teradata" => Ok(SqlDialect::Teradata),
        "tidb" => Ok(SqlDialect::TiDB),
        "trino" => Ok(SqlDialect::Trino),
        "tsql" | "mssql" => Ok(SqlDialect::TSQL),
        _ => Err(pyo3::exceptions::PyValueError::new_err(format!(
            "unknown dialect '{s}'. Supported: generic, snowflake, postgres, bigquery, \
             databricks, duckdb, mysql, redshift, athena, clickhouse, spark, trino, tsql, ..."
        ))),
    }
}
