(*
   --------------------------------------------------------------------------
   title: Complex Discount Calculation
   description: Multiple overlapping discount rules with caps
   order: 2
   --------------------------------------------------------------------------

   Real-world TRICKY example: Complex Discount Calculation with Overlapping Rules

   THE TRICKY PROBLEM:
   Multiple discount rules can apply simultaneously, and their interaction is complex:
   1. Volume discount: >= 10 items get 10% off, >= 50 items get 20% off
   2. Loyalty program: Bronze 5% off, Silver 10% off, Gold 15% off
   3. Seasonal discount: 25% off during sale season
   4. Maximum discount cap: Total discount cannot exceed 40%
   5. Minimum purchase: Discounts only apply if total >= $50

   Question: How many distinct pricing scenarios are there? Are all combinations handled?
   WITHOUT decomposition: Very hard to enumerate all cases manually!
   WITH decomposition: Automatically reveals all 20+ distinct pricing regions!

   This demonstrates decomposition's power for:
   - Discovering hidden edge cases in complex business logic
   - Ensuring completeness (all cases covered)
   - Finding unexpected interactions between rules
*)

type loyalty_tier = None | Bronze | Silver | Gold

(* Helper: Calculate loyalty discount percentage *)
let loyalty_discount tier =
  match tier with
  | None -> 0
  | Bronze -> 5
  | Silver -> 10
  | Gold -> 15

(* Helper: Calculate volume discount percentage *)
let volume_discount quantity =
  if quantity >= 50 then 20
  else if quantity >= 10 then 10
  else 0

(* THE TRICKY FUNCTION: Multiple overlapping discount rules *)
let calculate_final_price base_price quantity tier is_sale_season =
  if base_price < 50 then
    (* No discounts if under minimum *)
    base_price
  else
    (* Calculate each discount component *)
    let vol_disc = volume_discount quantity in
    let loyalty_disc = loyalty_discount tier in
    let seasonal_disc = if is_sale_season then 25 else 0 in

    (* Sum all discounts *)
    let total_disc = vol_disc + loyalty_disc + seasonal_disc in

    (* Apply 40% cap *)
    let final_disc = if total_disc > 40 then 40 else total_disc in

    (* Calculate final price *)
    base_price - (base_price * final_disc / 100)
[@@decomp top ~basis:[[%id volume_discount]; [%id loyalty_discount]] ()]

(* VARIATION 1: What if we inline the helper functions?
   This will create MANY more regions as it expands all combinations!
*)
let calculate_final_price_expanded base_price quantity tier is_sale_season =
  if base_price < 50 then
    base_price
  else
    let vol_disc =
      if quantity >= 50 then 20
      else if quantity >= 10 then 10
      else 0
    in
    let loyalty_disc =
      match tier with
      | None -> 0
      | Bronze -> 5
      | Silver -> 10
      | Gold -> 15
    in
    let seasonal_disc = if is_sale_season then 25 else 0 in
    let total_disc = vol_disc + loyalty_disc + seasonal_disc in
    let final_disc = if total_disc > 40 then 40 else total_disc in
    base_price - (base_price * final_disc / 100)
[@@decomp top ()]

(* VARIATION 2: Using ~prune to focus analysis
   This removes infeasible regions for cleaner analysis
*)
let calculate_final_price_valid base_price quantity tier is_sale_season =
  if base_price < 50 then
    base_price
  else
    let vol_disc = volume_discount quantity in
    let loyalty_disc = loyalty_discount tier in
    let seasonal_disc = if is_sale_season then 25 else 0 in
    let total_disc = vol_disc + loyalty_disc + seasonal_disc in
    let final_disc = if total_disc > 40 then 40 else total_disc in
    base_price - (base_price * final_disc / 100)
[@@decomp top ~prune:true ~basis:[[%id volume_discount]; [%id loyalty_discount]] ()]
