/// Floating-point classification shared at the arithmetic capability boundary.

///|
pub(all) enum FpClass {
  Finite
  Infinity
  NaN
} derive(Eq, Debug)

/// Rounding modes shared by checked/contextual arithmetic capabilities.

///|
pub(all) enum RoundingMode {
  ToNearestEven
  TowardZero
  TowardPositive
  TowardNegative
  AwayFromZero
} derive(Eq)

/// Lightweight arithmetic context for checked operations.

///|
pub struct ArithmeticContext {
  precision : Int32
  rounding : RoundingMode
  e_min : Int32?
  e_max : Int32?
  clamp : Bool
} derive(Eq)

/// Stage at which a proof-backed numerical evaluation failed.
///

///|
pub(all) enum CertificationStage {
  RangeReduction
  SeriesEvaluation
  EnclosurePropagation
  TargetRounding
} derive(Eq)

/// Structured reason for a proof-backed numerical evaluation failure.
///

///|
pub(all) enum CertificationFailureReason {
  RangeNotCertified
  SeriesDidNotConverge
  InvalidEnclosure
  ResourceLimit
  RefinementBudgetExhausted
} derive(Eq)

/// Details retained when certified evaluation cannot prove a target result.
///

///|
pub struct CertificationFailureDetail {
  operation : String
  stage : CertificationStage
  reason : CertificationFailureReason
  target_precision : Int32
  work_precision : Int32
  refinements : Int32
} derive(Eq)

/// Structured arithmetic error categories shared across Luna-Flow.

///|
pub enum ArithmeticErrorKind {
  DivisionByZero
  ParseError
  DomainError
  FormatError
  UnsupportedOperation
  UnorderedComparison
  CertificationFailure(CertificationFailureDetail)
} derive(Eq)

/// Structured error returned by checked/contextual arithmetic capabilities.

///|
pub struct ArithmeticError {
  kind : ArithmeticErrorKind
  message : String
} derive(Eq)

///|
pub fn ArithmeticContext::new(
  precision : Int32,
  rounding~ : RoundingMode = RoundingMode::ToNearestEven,
  e_min? : Int32,
  e_max? : Int32,
  clamp~ : Bool = false,
) -> ArithmeticContext {
  guard e_min is None || e_max is None || e_min.unwrap() <= e_max.unwrap() else {
    abort("ArithmeticContext::new: e_min must not exceed e_max")
  }
  { precision: Int32::max(1, precision), rounding, e_min, e_max, clamp, }
}

///|
pub fn ArithmeticContext::decimal32() -> ArithmeticContext {
  ArithmeticContext::new(7, e_min=-95, e_max=96, clamp=true)
}

///|
pub fn ArithmeticContext::decimal64() -> ArithmeticContext {
  ArithmeticContext::new(16, e_min=-383, e_max=384, clamp=true)
}

///|
pub fn ArithmeticContext::decimal128() -> ArithmeticContext {
  ArithmeticContext::new(34, e_min=-6143, e_max=6144, clamp=true)
}

///|
pub fn CertificationFailureDetail::new(
  operation : String,
  stage : CertificationStage,
  reason : CertificationFailureReason,
  target_precision : Int32,
  work_precision : Int32,
  refinements : Int32,
) -> CertificationFailureDetail {
  {
    operation,
    stage,
    reason,
    target_precision: Int32::max(1, target_precision),
    work_precision: Int32::max(1, work_precision),
    refinements: Int32::max(0, refinements),
  }
}

///|
pub fn CertificationFailureDetail::operation(
  self : CertificationFailureDetail,
) -> String {
  self.operation
}

///|
pub fn CertificationFailureDetail::stage(
  self : CertificationFailureDetail,
) -> CertificationStage {
  self.stage
}

///|
pub fn CertificationFailureDetail::reason(
  self : CertificationFailureDetail,
) -> CertificationFailureReason {
  self.reason
}

///|
pub fn CertificationFailureDetail::target_precision(
  self : CertificationFailureDetail,
) -> Int32 {
  self.target_precision
}

///|
pub fn CertificationFailureDetail::work_precision(
  self : CertificationFailureDetail,
) -> Int32 {
  self.work_precision
}

///|
pub fn CertificationFailureDetail::refinements(
  self : CertificationFailureDetail,
) -> Int32 {
  self.refinements
}

///|
pub fn ArithmeticError::division_by_zero(message : String) -> ArithmeticError {
  { kind: ArithmeticErrorKind::DivisionByZero, message, }
}

///|
pub fn ArithmeticError::parse_error(message : String) -> ArithmeticError {
  { kind: ArithmeticErrorKind::ParseError, message, }
}

///|
pub fn ArithmeticError::domain_error(message : String) -> ArithmeticError {
  { kind: ArithmeticErrorKind::DomainError, message, }
}

///|
pub fn ArithmeticError::format_error(message : String) -> ArithmeticError {
  { kind: ArithmeticErrorKind::FormatError, message, }
}

///|
pub fn ArithmeticError::unsupported(message : String) -> ArithmeticError {
  { kind: ArithmeticErrorKind::UnsupportedOperation, message, }
}

///|
pub fn ArithmeticError::unordered_comparison(
  message : String,
) -> ArithmeticError {
  { kind: ArithmeticErrorKind::UnorderedComparison, message, }
}

///|
pub fn ArithmeticError::certification_failure(
  detail : CertificationFailureDetail,
) -> ArithmeticError {
  {
    kind: ArithmeticErrorKind::CertificationFailure(detail),
    message: "certified evaluation failed for " + detail.operation(),
  }
}

///|
pub fn ArithmeticError::certification_failure_detail(
  self : ArithmeticError,
) -> CertificationFailureDetail? {
  match self.kind {
    ArithmeticErrorKind::CertificationFailure(detail) => Some(detail)
    _ => None
  }
}

///|
pub fn ArithmeticError::is_division_by_zero(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::DivisionByZero => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_parse_error(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::ParseError => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_domain_error(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::DomainError => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_format_error(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::FormatError => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_unsupported(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::UnsupportedOperation => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_unordered_comparison(self : ArithmeticError) -> Bool {
  match self.kind {
    ArithmeticErrorKind::UnorderedComparison => true
    _ => false
  }
}

///|
pub fn ArithmeticError::is_certification_failure(
  self : ArithmeticError,
) -> Bool {
  match self.kind {
    ArithmeticErrorKind::CertificationFailure(_) => true
    _ => false
  }
}

/// Checked square-root capability with explicit arithmetic context.
///
/// Domain validity is defined by each concrete `Self`. This trait does not
/// require a real-number ordering, zero comparison, or a universal notion of a
/// negative input. Implementations should report structured domain errors for
/// values that are invalid in their own mathematical domain.
///
/// For the built-in `Float` and `Double` instances, a NaN input propagates as
/// `Ok(NaN)`. A negative finite value or negative infinity returns
/// `DomainError`; signed zero, positive infinity, and NaN are passed to the
/// underlying square-root operation.

///|
pub(open) trait SqrtChecked {
  fn sqrt_checked(Self, ArithmeticContext) -> Result[Self, ArithmeticError]
}

/// Checked division capability with explicit arithmetic context.
///
/// Invalid division is defined by each concrete `Self`. This trait does not
/// require IEEE floating-point values, infinities, NaN, or a scalar total
/// order. Implementations should use structured errors for division cases that
/// are invalid in their own mathematical domain.
///
/// For the built-in `Float` and `Double` instances, any NaN operand propagates
/// as `Ok(NaN)`. `0/0` and `infinity/infinity` return `DomainError`; finite
/// non-zero divided by signed zero returns `DivisionByZero`; infinity divided
/// by signed zero returns the signed infinity in `Ok`.

///|
pub(open) trait DivChecked {
  fn div_checked(Self, Self, ArithmeticContext) -> Result[Self, ArithmeticError]
}

/// Checked scalar comparison capability.
///
/// Implementations return `-1`, `0`, or `1` on ordered inputs and a structured
/// error when no scalar ordering is available.

///|
pub(open) trait CompareChecked {
  fn compare_checked(Self, Self) -> Result[Int32, ArithmeticError]
}

/// Checked non-negative integer power capability.
///
/// `x^0` returns the multiplicative identity in this first checked-power layer,
/// including `0^0`.
///
/// For the built-in `Float` and `Double` instances, a quiet NaN base returns
/// `Ok(1)` for a zero exponent and `Ok(NaN)` for every other exponent. These
/// types do not distinguish signaling NaN, so every NaN is handled as quiet.
/// Overflow returns the signed infinity in `Ok`; underflow follows the
/// floating-point result.

///|
pub(open) trait PowNatChecked {
  fn pow_nat_checked(Self, UInt32, ArithmeticContext) -> Result[
    Self,
    ArithmeticError,
  ]
}

/// Checked signed integer power capability.
///
/// Negative exponents require reciprocal/division semantics. Zero base with a
/// negative exponent must report a structured error or a documented enclosure
/// fallback rather than silently producing an invalid scalar result.
///
/// For the built-in `Float` and `Double` instances, a quiet NaN base returns
/// `Ok(1)` for a zero exponent and `Ok(NaN)` for every other exponent. These
/// types do not distinguish signaling NaN, so every NaN is handled as quiet.
/// Overflow during a positive power returns the signed infinity in `Ok`. A
/// zero base with a negative exponent returns `DivisionByZero`.

///|
pub(open) trait PowIntChecked {
  fn pow_int_checked(Self, Int32, ArithmeticContext) -> Result[
    Self,
    ArithmeticError,
  ]
}

/// Checked parse capability parameterized by an arithmetic context.

///|
pub(open) trait ParseChecked {
  fn parse_checked(String, ArithmeticContext) -> Result[Self, ArithmeticError]
}

/// Enclosure containment relation.

///|
pub(open) trait Contains {
  fn contains(Self, Self) -> Bool
}

/// Enclosure overlap relation.

///|
pub(open) trait Overlaps {
  fn overlaps(Self, Self) -> Bool
}

/// Definite less-than relation for enclosure-like values.

///|
pub(open) trait DefinitelyLt {
  fn definitely_lt(Self, Self) -> Bool
}

/// Definite less-or-equal relation for enclosure-like values.

///|
pub(open) trait DefinitelyLe {
  fn definitely_le(Self, Self) -> Bool
}

/// Maybe-equal relation for enclosure-like values.

///|
pub(open) trait MaybeEq {
  fn maybe_eq(Self, Self) -> Bool
}