use crate::{
    data::OperatingSystemKind,
    datafile::datafile::DataFile,
    targeting::{conditions::TargetingCondition, models::OperatingSystemCPModel, TargetingData},
};

pub(crate) struct OperatingSystemCondition {
    os_kind: OperatingSystemKind,
}

impl OperatingSystemCondition {
    pub fn from_json(model: OperatingSystemCPModel) -> Option<Self> {
        let os_kind = OperatingSystemKind::from_str(&model.os)?;
        return Some(Self { os_kind });
    }
}

impl TargetingCondition for OperatingSystemCondition {
    fn check(&self, data: &TargetingData<impl DataFile>) -> Option<bool> {
        let os = data.visitor_data.operating_system.r().get()?;
        return Some(os.kind == self.os_kind);
    }
}

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

    use super::*;
    use rstest::rstest;

    #[rstest]
    #[case(1, None, false)]
    #[case(1, Some(OperatingSystemKind::Android), true)]
    #[case(1, Some(OperatingSystemKind::IOS), true)]
    #[case(1, Some(OperatingSystemKind::Linux), true)]
    #[case(1, Some(OperatingSystemKind::Mac), true)]
    #[case(1, Some(OperatingSystemKind::Windows), true)]
    #[case(1, Some(OperatingSystemKind::WindowsPhone), true)]
    #[case(2, Some(OperatingSystemKind::Android), true)]
    #[case(2, Some(OperatingSystemKind::IOS), false)]
    #[case(2, Some(OperatingSystemKind::Windows), false)]
    fn test_check(#[case] file_index: i32, #[case] os_kind: Option<OperatingSystemKind>, #[case] expected: bool) {
        let datafile = MockDataFile::default();
        let visitor = Visitor::new();
        if let Some(os_kind) = os_kind {
            visitor.add_data([BaseData::OperatingSystem(OperatingSystem::new(os_kind))].into_iter(), true);
        }
        assert_targeting(
            &format!("resources/conditions/mock_segment_os{file_index}.json"),
            &TargetingDataBuilder::new().build(&datafile, &visitor.rdata()),
            expected,
        );
    }
}
