use crate::{
    datafile::datafile::DataFile,
    targeting::{
        conditions::{
            visitor_scope_condition::{VisitScope, VisitorScopeCondition},
            TargetingCondition,
        },
        models::TargetPersonalizationCPModel,
        TargetingData,
    },
};

pub(crate) struct TargetPersonalizationCondition {
    personalization_id: u32,
    visitor_scope_condition: VisitorScopeCondition,
}

impl TargetPersonalizationCondition {
    pub fn from_json(model: TargetPersonalizationCPModel) -> Option<Self> {
        return Some(Self {
            personalization_id: model.personalization_id,
            visitor_scope_condition: VisitorScopeCondition::new(
                model.visit_params.visit_scope,
                model.visit_params.visit_count,
                VisitScope::CurrentVisit,
            ),
        });
    }
}

impl TargetingCondition for TargetPersonalizationCondition {
    fn check(&self, data: &TargetingData<impl DataFile>) -> Option<bool> {
        let personalization = data.visitor_data.personalizations.r().get(&self.personalization_id)?;
        return Some(personalization.assignment_time >= self.visitor_scope_condition.assignment_threshold(data));
    }
}

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

    use rstest::rstest;

    fn new_perso(id: u32, variation_id: u32, assignment_ts: u64) -> Personalization {
        Personalization::new(id, variation_id, millis_to_time(assignment_ts))
    }

    #[rstest]
    #[case(None, false)]
    #[case(Some(vec![]), false)]
    #[case(Some(vec![new_perso(1, 0, 300)]), false)]
    #[case(Some(vec![new_perso(1, 1, 300)]), false)]
    #[case(Some(vec![new_perso(2, 1, 50)]), false)]
    #[case(Some(vec![new_perso(2, 1, 100)]), true)]
    #[case(Some(vec![new_perso(2, 0, 1000)]), true)]
    fn test_check(#[case] personalizations: Option<Vec<Personalization>>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        visitor.add_data(std::iter::once(BaseData::VisitorVisits(new_visitor_visits())), true);
        if let Some(personalizations) = personalizations {
            visitor.add_data(personalizations.into_iter().map(|p| BaseData::Personalization(p)), true);
        }
        assert_targeting(
            "resources/conditions/mock_segment_target_perso.json",
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
