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

// IntTraits.hpp
// Trait specializations for the Int type

#ifndef SANGI_INT_TRAITS_HPP
#define SANGI_INT_TRAITS_HPP

#include <math/core/mp/Int/IntBase.hpp>

namespace sangi {

    // Only forward declarations here; the implementation lives in traits.hpp
    // Prevents duplicate definitions of template specializations
    template<typename T> struct numeric_traits;
    template<typename T> struct numeric_state_traits;

    // numeric_traits specialization for the Int type
    template<>
    struct numeric_traits<Int> {
        using value_type = Int;
        using category = integer_tag;

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

        static Int zero() { return Int(0); }
        static Int one() { return Int(1); }
        static Int epsilon() { return Int(1); } // The smallest unit of an integer is 1

        // Infinity returns a special value
        static Int infinity() { return Int::infinity(); }

        // NaN returns a special value
        static Int quiet_NaN() { return Int::nan(); }

        static Int abs(const Int& value) {
            // Handle special states
            if (value.isNaN()) {
                return value;  // For NaN, return as is
            }

            // Adjust the sign of infinity
            if (value.isInfinite()) {
                if (value.getState() == NumericState::NegativeInfinity) {
                    return Int::infinity();  // Convert negative infinity to positive infinity
                }
                return value;  // Positive infinity is returned as is
            }

            if (value.isZero()) {
                return Int(0);
            }

            // Handle normal values
            if (value.getSign() < 0) {
                // Convert negative value to positive
                Int result = value;
                result.setSign(1);
                return result;
            }

            return value;
        }

        static Int conj(const Int& value) { return value; } // The conjugate of an integer is itself
        static Int norm(const Int& value) {
            // The norm of an integer is its absolute value
            return abs(value);
        }
        static bool pivotBetter(const Int& a, const Int& b) {
            return abs(a) > abs(b);
        }
    };

    // numeric_state_traits specialization for the Int type
    template<>
    struct numeric_state_traits<Int> {
        static bool isNormal(const Int& value) { return value.isNormal(); }
        static bool isNaN(const Int& value) { return value.isNaN(); }
        static bool isInfinite(const Int& value) { return value.isInfinite(); }
        static bool isDivergent(const Int& value) { return value.isDivergent(); }
        static bool isOverflow(const Int& /*value*/) { return false; } // Int does not overflow internally

        static NumericState getState(const Int& value) { return value.getState(); }
        static NumericError getError(const Int& value) { return value.getError(); }
        static int getSign(const Int& value) { return value.getSign(); }
        static DivergenceDetail getDivergenceDetail(const Int& value) { return value.getDivergenceDetail(); }
    };

} // namespace sangi

#endif // SANGI_INT_TRAITS_HPP