use super::SqlNode;
use crate::physical_plan::SqlEvaluatorVisitor;
use crate::planner::query_tools::QueryTools;
use crate::planner::sql_templates::PlanSqlTemplates;
use crate::planner::MemberSymbol;
use cubenativeutils::CubeError;
use std::any::Any;
use std::rc::Rc;

/// Wraps a measure's rendered SQL in the `measure_filters` declared
/// on its data-model definition (e.g. `FILTER (WHERE ...)` / CASE
/// gating depending on the dialect templates).
pub struct MeasureFilterSqlNode {
    input: Rc<dyn SqlNode>,
}

impl MeasureFilterSqlNode {
    pub fn new(input: Rc<dyn SqlNode>) -> Rc<Self> {
        Rc::new(Self { input })
    }

    pub fn input(&self) -> &Rc<dyn SqlNode> {
        &self.input
    }
}

impl SqlNode for MeasureFilterSqlNode {
    fn to_sql(
        &self,
        visitor: &SqlEvaluatorVisitor,
        node: &Rc<MemberSymbol>,
        query_tools: Rc<QueryTools>,
        node_processor: Rc<dyn SqlNode>,
        templates: &PlanSqlTemplates,
    ) -> Result<String, CubeError> {
        let res = match node.as_ref() {
            MemberSymbol::Measure(ev) => {
                let measure_filters = ev.measure_filters();
                if !measure_filters.is_empty() {
                    let inner_visitor = visitor.with_arg_needs_paren_safe(false);
                    let input = self.input.to_sql(
                        &inner_visitor,
                        node,
                        query_tools.clone(),
                        node_processor.clone(),
                        templates,
                    )?;
                    let filters = measure_filters
                        .iter()
                        .map(|filter| -> Result<String, CubeError> {
                            Ok(format!(
                                "({})",
                                filter.eval(
                                    &inner_visitor,
                                    node_processor.clone(),
                                    query_tools.clone(),
                                    templates
                                )?
                            ))
                        })
                        .collect::<Result<Vec<_>, _>>()?
                        .join(" AND ");
                    let result = if input.as_str() == "*" {
                        "1".to_string()
                    } else {
                        input
                    };
                    format!("CASE WHEN {} THEN {} END", filters, result)
                } else {
                    // Passthrough — propagate visitor unchanged.
                    self.input.to_sql(
                        visitor,
                        node,
                        query_tools.clone(),
                        node_processor.clone(),
                        templates,
                    )?
                }
            }
            _ => {
                return Err(CubeError::internal(format!(
                    "Measure filter node processor called for wrong node",
                )));
            }
        };
        Ok(res)
    }

    fn as_any(self: Rc<Self>) -> Rc<dyn Any> {
        self.clone()
    }

    fn childs(&self) -> Vec<Rc<dyn SqlNode>> {
        vec![self.input.clone()]
    }
}
