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

pub(crate) struct KcsHeatRangeCondition {
    goal_id: u32,
    key_moment_id: u32,
    lower_bound: f64,
    upper_bound: f64,
}

impl KcsHeatRangeCondition {
    pub fn from_json(model: HeatSliceCPModel) -> Option<Self> {
        return Some(Self {
            goal_id: model.goal_id,
            key_moment_id: model.key_moment_id,
            lower_bound: model.lower_bound,
            upper_bound: model.upper_bound,
        });
    }
}

impl TargetingCondition for KcsHeatRangeCondition {
    fn check(&self, data: &TargetingData<impl DataFile>) -> Option<bool> {
        let kcs_heat = data.visitor_data.kcs_heat.r().get()?;
        return Some(
            kcs_heat
                .values
                .get(&self.key_moment_id)
                .and_then(|goal_scores| goal_scores.get(&self.goal_id))
                .map_or(false, |score| *score >= self.lower_bound && *score <= self.upper_bound),
        );
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use crate::{
        data::{kcs_heat::KcsHeat, BaseData},
        datafile::datafile_test_utils::MockDataFile,
        storage::visitor::Visitor,
        targeting::TargetingDataBuilder,
        utils::test_utils::assert_targeting,
    };

    use rstest::rstest;

    #[rstest]
    #[case(None, false)]
    #[case(Some(HashMap::new()), false)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335721, 7.5)])),
    ])), true)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335721, 5.0)])),
    ])), true)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335721, 10.0)])),
    ])), true)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335721, 4.9)])),
    ])), false)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335721, 10.1)])),
    ])), false)]
    #[case(Some(HashMap::from([
        (1098, HashMap::from([(335720, 7.5)])),
    ])), false)]
    #[case(Some(HashMap::from([
        (1099, HashMap::from([(335721, 7.5)])),
    ])), false)]
    fn test_check(#[case] values: Option<HashMap<u32, HashMap<u32, f64>>>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        if let Some(values) = values {
            visitor.add_data([BaseData::KcsHeat(KcsHeat::new(values))].into_iter(), true);
        }
        assert_targeting(
            "resources/conditions/mock_segment_heat_slice.json",
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
