use nu_plugin::EngineInterface;
use nu_protocol::{PipelineData, Spanned, engine::Closure};
use skim::prelude::*;

use crate::nu_item::NuItem;

pub struct PredicateBasedSelector {
    pub engine: EngineInterface,
    pub predicate: Spanned<Closure>,
}

impl Selector for PredicateBasedSelector {
    fn should_select(&self, _index: usize, item: &dyn SkimItem) -> bool {
        let Some(nu_item) = item.as_any().downcast_ref::<NuItem>() else {
            return false;
        };
        let Ok(result) = self.engine.eval_closure_with_stream(
            &self.predicate,
            vec![],
            PipelineData::Value(nu_item.value.clone(), None),
            true,
            true,
        ) else {
            return false;
        };
        match result {
            PipelineData::Value(value, _) => value.is_true(),
            _ => false,
        }
    }
}

pub struct CombinedSelector(pub DefaultSkimSelector, pub PredicateBasedSelector);

impl Selector for CombinedSelector {
    fn should_select(&self, index: usize, item: &dyn SkimItem) -> bool {
        self.0.should_select(index, item) || self.1.should_select(index, item)
    }
}
