// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later

// RationalTraits.hpp
// Trait specializations for the Rational type

#ifndef SANGI_RATIONAL_TRAITS_HPP
#define SANGI_RATIONAL_TRAITS_HPP

#include <math/core/mp/Rational/RationalBase.hpp>

namespace sangi {

    // Forward declarations
    struct real_tag;
    template<typename T> struct numeric_traits;
    template<typename T> struct numeric_state_traits;

    // numeric_traits specialization for Rational
    template<>
    struct numeric_traits<Rational> {
        using value_type = Rational;
        using category = real_tag;

        static constexpr bool is_supported = true;
        static constexpr bool is_complex = false;
        static constexpr bool is_integer = false;
        static constexpr bool is_floating_point = false;

        static Rational zero() { return Rational(); }
        static Rational one() { return Rational(1); }
        static Rational epsilon() { return Rational(); } // The rationals are dense: no smallest unit → 0

        static Rational abs(const Rational& value) {
            return sangi::abs(value);
        }

        /// Pivot selection: a smaller height (max(|numerator|, |denominator|)) is a better pivot.
        /// Helps suppress coefficient blow-up.
        static bool pivotBetter(const Rational& a, const Rational& b) {
            return height(a) < height(b);
        }

        static Rational conj(const Rational& value) {
            return value; // The conjugate of a real number is itself
        }

        static Rational norm(const Rational& value) {
            return abs(value);
        }

        static bool isNaN(const Rational& value) {
            return value.isNaN();
        }

        static bool isInfinite(const Rational& /*value*/) {
            return false; // Rational has no infinities
        }

        static bool isFinite(const Rational& value) {
            return !value.isNaN();
        }

        static int getSign(const Rational& value) {
            if (value.isNaN()) return 0;
            if (value.isZero()) return 0;
            return value.isNegative() ? -1 : 1;
        }
    };

    // numeric_state_traits specialization for Rational
    template<>
    struct numeric_state_traits<Rational> {
        static bool isNormal(const Rational& value) { return !value.isNaN() && !value.isZero(); }
        static bool isNaN(const Rational& value) { return value.isNaN(); }
        static bool isInfinite(const Rational& /*value*/) { return false; }
        static bool isDivergent(const Rational& /*value*/) { return false; }
        static bool isOverflow(const Rational& /*value*/) { return false; }

        static NumericState getState(const Rational& value) {
            if (value.isNaN()) return NumericState::NaN;
            return NumericState::Normal;
        }

        static NumericError getError(const Rational& value) {
            if (value.isNaN()) return NumericError::ExplicitNaN;
            return NumericError::None;
        }

        static int getSign(const Rational& value) {
            if (value.isNaN()) return 0;
            if (value.isZero()) return 0;
            return value.isNegative() ? -1 : 1;
        }
    };

} // namespace sangi

#endif // SANGI_RATIONAL_TRAITS_HPP
