use crate::{
    datafile::datafile::DataFile,
    targeting::{
        conditions::{string_value_condition::StringValueCondition, TargetingCondition},
        models::PageTitleCPModel,
        TargetingData,
    },
};

pub(crate) struct PageTitleCondition {
    string_condition: StringValueCondition,
}

impl PageTitleCondition {
    pub fn from_json(model: PageTitleCPModel) -> Option<Self> {
        let string_condition = StringValueCondition::new(model.title, model.match_type)?;
        Some(Self { string_condition })
    }
}

impl TargetingCondition for PageTitleCondition {
    fn check(&self, data: &TargetingData<impl DataFile>) -> Option<bool> {
        let page_view_visits = data.visitor_data.page_view_visits.r();
        let latest = page_view_visits.iter().max_by_key(|pvv| pvv.last_ts())?;
        return Some(self.string_condition.check(latest.page_view().title.as_deref()?));
    }
}

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

    use rstest::rstest;

    #[rstest]
    #[case(None, false)]
    #[case(Some(PageView::new_with_url("url")), false)]
    #[case(Some(PageView::new("url", "Delicious Apple Pie".into(), vec![])), true)]
    #[case(Some(PageView::new("url", "Apple Pie".into(), vec![])), false)]
    #[case(Some(PageView::new("url", "".into(), vec![])), false)]
    #[case(Some(PageView::new("url", "".into(), vec![])), false)]
    fn test_check(#[case] page_view: Option<PageView>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        if let Some(page_view) = page_view {
            visitor.add_data([BaseData::PageView(page_view)].into_iter(), true);
        }
        assert_targeting(
            "resources/conditions/mock_segment_page_title.json",
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }

    #[rstest]
    #[case(
        PageView::new("url1", Some("Apple Pie".to_owned()), vec![]),
        PageView::new("url2", Some("Delicious Apple Pie".to_owned()), vec![]),
        true
    )]
    #[case(
        PageView::new("url1", Some("Delicious Apple Pie"), vec![]),
        PageView::new("url2", Some("Apple Pie".to_owned()), vec![]),
        false
    )]
    fn test_check_latest(#[case] page_view1: PageView, #[case] page_view2: PageView, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        let time = millis_to_time_opt(1234567890);
        visitor.add_data(
            [BaseData::PageViewVisit(PageViewVisit::new(page_view1, 1, time)), BaseData::PageView(page_view2)]
                .into_iter(),
            true,
        );
        assert_targeting(
            "resources/conditions/mock_segment_page_title.json",
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
