use serde_json::Value;

/// Supported comparison operators used to describe a condition.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConditionOperator {
    Eq,
    Neq,
    Gt,
    Lt,
    In,
    Gte,
    Lte,
    Like,
    ILike,
    Is,
    Contains,
    Contained,
}

/// Represents a filter condition used for building SQL queries.
#[derive(Debug, Clone, PartialEq)]
pub struct Condition {
    pub column: String,
    pub operator: ConditionOperator,
    pub values: Vec<Value>,
    pub negated: bool,
    pub auto_cast_uuid_value_to_text: bool,
    /// Short Postgres cast name (`float8`, `int8`, `boolean`, `timestamptz`, ...) to
    /// apply to `$n` placeholders when the bound JSON value is a string. Lets the
    /// WHERE builder emit `$1::float8` so Postgres parses `"0.75"` into the target
    /// column's type instead of rejecting a `double precision = text` comparison.
    /// `None` preserves bare-placeholder behavior.
    pub pg_cast: Option<String>,
}

impl Condition {
    /// Builds an equality condition for the given column and value.
    pub fn eq(column: impl Into<String>, value: impl Into<Value>) -> Self {
        Self {
            column: column.into(),
            operator: ConditionOperator::Eq,
            values: vec![value.into()],
            negated: false,
            auto_cast_uuid_value_to_text: true,
            pg_cast: None,
        }
    }

    /// Builds a condition using the provided values and operator.
    pub fn new(
        column: impl Into<String>,
        operator: ConditionOperator,
        values: Vec<Value>,
        negated: bool,
    ) -> Self {
        Self {
            column: column.into(),
            operator,
            values,
            negated,
            auto_cast_uuid_value_to_text: true,
            pg_cast: None,
        }
    }

    /// Enables or disables automatic UUID value casting to text in predicates.
    pub fn with_uuid_value_text_cast(mut self, enabled: bool) -> Self {
        self.auto_cast_uuid_value_to_text = enabled;
        self
    }

    /// Stamps the Postgres cast keyword used when rendering `$n` placeholders for
    /// JSON string values (see [`Self::pg_cast`]). Pass `None` to clear the cast.
    pub fn with_pg_cast(mut self, pg_cast: Option<impl Into<String>>) -> Self {
        self.pg_cast = pg_cast.map(Into::into);
        self
    }
}
