use crate::{
    datafile::datafile::DataFile,
    targeting::{
        conditions::{number_condition::NumberCondition, TargetingCondition},
        models::PageViewsCPModel,
        TargetingData,
    },
};

pub(crate) struct PageViewNumberCondition {
    number_condition: NumberCondition<u32>,
}

impl PageViewNumberCondition {
    pub fn from_json(model: PageViewsCPModel) -> Option<Self> {
        let number_condition = NumberCondition::new(model.page_count, model.match_type)?;
        return Some(Self { number_condition });
    }
}

impl TargetingCondition for PageViewNumberCondition {
    fn check(&self, data: &TargetingData<impl DataFile>) -> Option<bool> {
        let count = data.visitor_data.page_view_visits.r().iter().map(|pvv| pvv.count()).sum();
        return Some(self.number_condition.check(count));
    }
}

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

    use rstest::rstest;

    #[rstest]
    // EXACT
    #[case(Some(vec![PageViewVisit::new(PageView::new_with_url("1"), 19, None)]), false)]
    #[case(Some(vec![
        PageViewVisit::new(PageView::new_with_url("1"), 10, None),
        PageViewVisit::new(PageView::new_with_url("2"), 10, None),
    ]), true)]
    #[case(Some(vec![PageViewVisit::new(PageView::new_with_url("1"), 20, None)]), true)]
    // GREATER
    #[case(Some(vec![
        PageViewVisit::new(PageView::new_with_url("1"), 20, None),
        PageViewVisit::new(PageView::new_with_url("2"), 9, None),
    ]), false)]
    #[case(Some(vec![
        PageViewVisit::new(PageView::new_with_url("1"), 20, None),
        PageViewVisit::new(PageView::new_with_url("2"), 9, None),
        PageViewVisit::new(PageView::new_with_url("3"), 2, None),
    ]), true)]
    // LOWER
    #[case(None, true)]
    #[case(Some(vec![
        PageViewVisit::new(PageView::new_with_url("1"), 5, None),
        PageViewVisit::new(PageView::new_with_url("2"), 3, None),
        PageViewVisit::new(PageView::new_with_url("2"), 2, None),
    ]), false)]
    #[case(Some(vec![
        PageViewVisit::new(PageView::new_with_url("1"), 5, None),
        PageViewVisit::new(PageView::new_with_url("2"), 3, None),
    ]), true)]

    fn test_check(#[case] page_view_visits: Option<Vec<PageViewVisit>>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        if let Some(page_view_visits) = page_view_visits {
            visitor.add_data(page_view_visits.into_iter().map(|pvv| BaseData::PageViewVisit(pvv)), true);
        }
        assert_targeting(
            "resources/conditions/mock_segment_number_pages.json",
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
