use crate::{
    datafile::datafile::DataFile,
    targeting::{conditions::TargetingCondition, models::ConversionsCPModel},
};

pub(crate) struct ConversionCondition {
    goal_id: Option<u32>,
}

impl ConversionCondition {
    pub fn from_json(model: ConversionsCPModel) -> Self {
        return Self { goal_id: model.goal_id };
    }
}

impl TargetingCondition for ConversionCondition {
    fn check(&self, data: &crate::targeting::TargetingData<impl DataFile>) -> Option<bool> {
        Some(data.visitor_data.conversions.iter().any(|c| self.goal_id.map_or(true, |goal_id| goal_id == c.goal_id)))
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        data::{BaseData, Conversion},
        datafile::datafile_test_utils::MockDataFile,
        storage::visitor::Visitor,
        targeting::TargetingDataBuilder,
        utils::test_utils::assert_targeting,
    };

    use rstest::rstest;

    #[rstest]
    #[case(1, None, false)]
    #[case(1, Some(vec![Conversion::new(1000)]), true)]
    #[case(1, Some(vec![Conversion::new(999)]), false)]
    #[case(2, Some(vec![Conversion::new(999)]), true)]
    #[case(2, Some(vec![]), false)]
    fn test_check(#[case] file_index: i32, #[case] conversions: Option<Vec<Conversion>>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        if let Some(conversions) = conversions {
            visitor.add_data(conversions.into_iter().map(|c| BaseData::Conversion(c)), true);
        }
        assert_targeting(
            &format!("resources/conditions/mock_segment_conversion{file_index}.json"),
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
