///|
pub enum Rule {
  AmountAtLeast(String, Int)
  AmountAtMost(String, Int)
  CustomerFrequency(String, Int, Int)
  AccountFrequency(String, Int, Int)
  CustomerVolume(String, Int, Int)
  RegionIs(String, String)
  CurrencyIs(String, String)
  RapidMovement(String, Int, Int)
  Structuring(String, Int, Int, Int)
} derive(Debug, Eq)

///|
pub fn Rule::amount_at_least(id : String, minimum : Int) -> Rule {
  AmountAtLeast(id, minimum)
}

///|
pub fn Rule::amount_at_most(id : String, maximum : Int) -> Rule {
  AmountAtMost(id, maximum)
}

///|
pub fn Rule::customer_frequency(
  id : String,
  minimum : Int,
  window_seconds : Int,
) -> Rule {
  CustomerFrequency(id, minimum, window_seconds)
}

///|
pub fn Rule::account_frequency(
  id : String,
  minimum : Int,
  window_seconds : Int,
) -> Rule {
  AccountFrequency(id, minimum, window_seconds)
}

///|
pub fn Rule::customer_volume(
  id : String,
  minimum : Int,
  window_seconds : Int,
) -> Rule {
  CustomerVolume(id, minimum, window_seconds)
}

///|
pub fn Rule::region_is(id : String, region : String) -> Rule {
  RegionIs(id, region)
}

///|
pub fn Rule::currency_is(id : String, currency : String) -> Rule {
  CurrencyIs(id, currency)
}

///|
pub fn Rule::rapid_movement(
  id : String,
  amount : Int,
  window_seconds : Int,
) -> Rule {
  RapidMovement(id, amount, window_seconds)
}

///|
pub fn Rule::structuring(
  id : String,
  unit : Int,
  minimum : Int,
  window_seconds : Int,
) -> Rule {
  Structuring(id, unit, minimum, window_seconds)
}

///|
/// Parse the stable threshold DSL form `amount>=N`.
pub fn Rule::parse(text : String) -> Rule raise {
  if text.has_prefix("amount>=") {
    AmountAtLeast(text, @string.parse_int(text[8:]))
  } else {
    fail("unsupported rule: \\{text}")
  }
}

///|
pub fn Rule::id(self : Rule) -> String {
  match self {
    AmountAtLeast(id, _) => id
    AmountAtMost(id, _) => id
    CustomerFrequency(id, _, _) => id
    AccountFrequency(id, _, _) => id
    CustomerVolume(id, _, _) => id
    RegionIs(id, _) => id
    CurrencyIs(id, _) => id
    RapidMovement(id, _, _) => id
    Structuring(id, _, _, _) => id
  }
}

///|
pub fn Rule::description(self : Rule) -> String {
  match self {
    AmountAtLeast(_, n) => "amount at least \{n}"
    AmountAtMost(_, n) => "amount at most \{n}"
    CustomerFrequency(_, n, w) => "customer frequency \{n} in \{w}s"
    AccountFrequency(_, n, w) => "account frequency \{n} in \{w}s"
    CustomerVolume(_, n, w) => "customer volume \{n} in \{w}s"
    RegionIs(_, r) => "region is \{r}"
    CurrencyIs(_, c) => "currency is \{c}"
    RapidMovement(_, a, w) => "rapid movement \{a} in \{w}s"
    Structuring(_, u, n, w) => "structuring unit \{u}, \{n} times in \{w}s"
  }
}