use crate::{
    filter::{
        apply_filtering_function, apply_function, error::Error, match_operator, Expression,
        Filtering,
    },
    ColumnFrame, Key,
};

pub struct ColumnFrameFiltering<'a> {
    pub column_frame: &'a ColumnFrame,
}
impl<'a> Filtering for ColumnFrameFiltering<'a> {
    fn prepare_indicies(&self, expression: &Expression) -> Result<Vec<usize>, Error> {
        if expression.left.is_function() || expression.left.is_mod() {
            let indicies = apply_function(self, expression);
            tracing::trace!("Function applied, indices: {:?}", indicies);
            return indicies;
        }
        let key: Key = expression
            .left
            .as_key()
            .ok_or(Error::Parser("Cannot create key".to_string()))?
            .into();
        let column = self
            .column_frame
            .get_single_column(&key)
            .ok_or(Error::Parser(format!("Column not found: {key}")))?;
        let right = expression.filter_argument()?;

        let indicies = column
            .iter()
            .enumerate()
            .filter_map(|(i, value)| match_operator(i, value, &right, expression.operator))
            .collect::<Vec<_>>();
        tracing::trace!(
            "Expression applied, indices: {:?} for expression: {:?}",
            indicies,
            expression
        );
        Ok(indicies)
    }

    fn apply_function(&self, expression: &Expression) -> Result<Vec<usize>, Error> {
        let key: Key = expression
            .left
            .as_key()
            .ok_or(Error::Parser("Cannot create key".to_string()))?
            .into();
        let column = self
            .column_frame
            .get_single_column(&key)
            .ok_or(Error::Parser(format!("Column not found: {key}")))?;

        Ok(column
            .iter()
            .enumerate()
            .filter_map(|(i, value)| apply_filtering_function(i, value, expression))
            .collect::<Vec<_>>())
    }
}
