1use crate::bundling::{validate_bundle, Bundle};
4use crate::eligibility::{is_eligible, EligibilityContext, EligibilityRule};
5use crate::pricing::{calculate_final_price, PricingContext, PricingRule};
6use crate::rules::{evaluate_rule, CatalogRule, RuleContext};
7use uuid::Uuid;
8
9pub struct CatalogEngine {
11 pricing_rules: Vec<PricingRule>,
12 eligibility_rules: Vec<EligibilityRule>,
13 bundles: Vec<Bundle>,
14 catalog_rules: Vec<CatalogRule>,
15}
16
17impl CatalogEngine {
18 pub fn new() -> Self {
20 Self {
21 pricing_rules: Vec::new(),
22 eligibility_rules: Vec::new(),
23 bundles: Vec::new(),
24 catalog_rules: Vec::new(),
25 }
26 }
27
28 pub fn add_pricing_rule(&mut self, rule: PricingRule) {
30 self.pricing_rules.push(rule);
31 }
32
33 pub fn add_eligibility_rule(&mut self, rule: EligibilityRule) {
35 self.eligibility_rules.push(rule);
36 }
37
38 pub fn add_bundle(&mut self, bundle: Bundle) -> Result<(), String> {
40 validate_bundle(&bundle)?;
41 self.bundles.push(bundle);
42 Ok(())
43 }
44
45 pub fn add_catalog_rule(&mut self, rule: CatalogRule) {
47 self.catalog_rules.push(rule);
48 }
49
50 pub fn check_eligibility(
52 &self,
53 product_offering_id: Uuid,
54 context: &EligibilityContext,
55 ) -> bool {
56 self.eligibility_rules
57 .iter()
58 .filter(|rule| rule.product_offering_id == product_offering_id)
59 .all(|rule| is_eligible(rule, context))
60 }
61
62 pub fn calculate_price(
64 &self,
65 product_offering_id: Uuid,
66 context: &PricingContext,
67 ) -> Option<crate::pricing::Money> {
68 self.pricing_rules
69 .iter()
70 .find(|rule| rule.product_offering_id == product_offering_id)
71 .map(|rule| calculate_final_price(rule, context))
72 }
73
74 pub fn get_bundles_for_product(&self, product_offering_id: Uuid) -> Vec<&Bundle> {
76 self.bundles
77 .iter()
78 .filter(|bundle| {
79 bundle
80 .products
81 .iter()
82 .any(|bp| bp.product_offering_id == product_offering_id)
83 })
84 .collect()
85 }
86
87 pub fn evaluate_rules(&self, context: &RuleContext) -> Vec<&CatalogRule> {
89 self.catalog_rules
90 .iter()
91 .filter(|rule| {
92 matches!(
93 evaluate_rule(rule, context),
94 crate::rules::RuleResult::Matched { .. }
95 )
96 })
97 .collect()
98 }
99}
100
101impl Default for CatalogEngine {
102 fn default() -> Self {
103 Self::new()
104 }
105}