use crate::value::Value;

#[derive(Clone)]
pub enum SetField {
    Value(String, Value),
    Raw(String, String),
}

#[derive(Clone)]
pub struct Set {
    fields: Vec<SetField>,
}

impl Set {
    pub fn new() -> Self {
        Self { fields: vec![] }
    }

    pub fn field(mut self, col: &str, val: impl Into<Value>) -> Self {
        self.fields.push(SetField::Value(col.into(), val.into()));
        self
    }

    pub fn nullable_field(mut self, col: &str, val: Option<impl Into<Value>>) -> Self {
        let v = val.map(Into::into).unwrap_or(Value::Null);
        self.fields.push(SetField::Value(col.into(), v));
        self
    }

    pub fn raw_expr(mut self, col: &str, expr: &str) -> Self {
        self.fields.push(SetField::Raw(col.into(), expr.into()));
        self
    }

    pub fn is_empty(&self) -> bool {
        self.fields.is_empty()
    }

    pub fn build(&self, param_start: usize) -> (String, Vec<Value>, usize) {
        let mut parts: Vec<String> = vec![];
        let mut values: Vec<Value> = vec![];
        let mut n = param_start;
        for field in &self.fields {
            match field {
                SetField::Value(col, val) => {
                    parts.push(format!("{} = ?{}", col, n));
                    values.push(val.clone());
                    n += 1;
                }
                SetField::Raw(col, expr) => {
                    parts.push(format!("{} = {}", col, expr));
                }
            }
        }
        (parts.join(", "), values, n)
    }
}

impl Default for Set {
    fn default() -> Self { Self::new() }
}
