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

// Int.hpp
// Main header file for the multi-precision integer library
//
// This file aggregates all features of the multi-precision integer library
// so that they can be included from a single header.
//
// Main features:
// - Multi-precision integer class (Int)
// - Basic arithmetic operations
// - Handling of special states (NaN, infinity, etc.)
// - Stream I/O
// - Number-theoretic functions
// - Performance optimizations

#ifndef SANGI_INT_HPP
#define SANGI_INT_HPP

// State management system
#include <math/core/numeric_state.hpp>
#include <math/core/mp/error.hpp>
// Basic Int-related headers
#include <math/core/mp/Int/IntBase.hpp>
#include <math/core/mp/Int/IntOps.hpp>
#include <math/core/mp/Int/IntIO.hpp>
#include <math/core/mp/Int/IntSpecialStates.hpp>
#include <math/core/mp/Int/IntDivision.hpp>

namespace sangi {

// Version information
struct IntVersion {
    static constexpr int major = 2;  // Major version bumped due to introduction of the state management system
    static constexpr int minor = 0;
    static constexpr int patch = 0;
    
    static constexpr const char* string() {
        return "2.0.0";
    }
    
    static constexpr const char* name() {
        return "MKL Algebra Int Library";
    }
    
    static constexpr const char* description() {
        return "High-performance multiple precision integer library with state management for C++20/23";
    }
};

/**
 * @brief Overview of the Int class
 *
 * This library provides a high-performance multi-precision integer. Main features:
 *
 * - Arbitrary-precision integer arithmetic
 * - Support for C++20/23 concepts
 * - Special state management (NaN, infinity, divergence, etc.)
 * - Optimization for small integers
 * - High-performance algorithms (Karatsuba, FFT, etc.)
 * - Optimization via SIMD instructions and parallelization
 *
 * Usage example:
 *
 * ```cpp
 * using namespace sangi;
 *
 * // Basic operations
 * Int a(123456789);
 * Int b("987654321");
 * Int c = a + b;
 *
 * // I/O
 * std::cout << "a + b = " << c << std::endl;
 *
 * // Hexadecimal display
 * std::cout << "hex: " << c.toString(16) << std::endl;
 *
 * // Bit operations
 * Int d = (a << 100) | b;
 *
 * // Handling of special states
 * Int x = Int::infinity();   // Positive infinity
 * Int y = Int::negInfinity(); // Negative infinity
 * Int z = x + y;             // NaN (indeterminate)
 *
 * if (z.isNaN()) {
 *     std::cout << "The result is indeterminate" << std::endl;
 * }
 * ```
 *
 * Refer to the documentation for detailed usage instructions.
 */

// Utility functions

/**
 * @brief Compute the greatest common divisor (GCD)
 * @param a First argument
 * @param b Second argument
 * @return The greatest common divisor
 */
Int gcd(const Int& a, const Int& b);

/**
 * @brief Compute the least common multiple (LCM)
 * @param a First argument
 * @param b Second argument
 * @return The least common multiple
 */
Int lcm(const Int& a, const Int& b);

/**
 * @brief Exponentiation
 * @param base Base
 * @param exponent Exponent
 * @return base^exponent
 */
Int pow(const Int& base, const Int& exponent);

/**
 * @brief Modular exponentiation
 * @param base Base
 * @param exponent Exponent
 * @param modulus Modulus
 * @return (base^exponent) mod modulus
 */
Int powMod(const Int& base, const Int& exponent, const Int& modulus);

/**
 * @brief Return the bit length of the two's-complement representation, including the sign bit
 * @param value The target value
 * @return Bit length
 */
size_t bitCount(const Int& value);

/**
 * @brief Primality test (probabilistic algorithm)
 * @param value The value to test
 * @param iterations Number of iterations (affects accuracy)
 * @return true if probably prime
 */
bool isProbablePrime(const Int& value, int iterations);

// Detection and handling of special states

/**
 * @brief Detect special states
 * @param value The target value
 * @return true if a normal value, false if a special state (NaN, infinity, etc.)
 */
bool isNormal(const Int& value);

/**
 * @brief Detect NaN (Not a Number) state
 * @param value The target value
 * @return true if NaN
 */
bool isNaN(const Int& value);

/**
 * @brief Detect infinity state
 * @param value The target value
 * @return true if positive or negative infinity
 */
bool isInfinite(const Int& value);

/**
 * @brief Detect positive infinity state
 * @param value The target value
 * @return true if positive infinity
 */
bool isPosInfinite(const Int& value);

/**
 * @brief Detect negative infinity state
 * @param value The target value
 * @return true if negative infinity
 */
bool isNegInfinite(const Int& value);

/**
 * @brief Detect overflow state
 * @param value The target value
 * @return true if overflow has occurred
 */
bool isOverflow(const Int& value);

/**
 * @brief Detect divergence state
 * @param value The target value
 * @return true if diverging (not converging or converging very slowly)
 */
bool isDivergent(const Int& value);

/**
 * @brief Obtain a string describing the special state
 * @param value The target value
 * @return A string representing the state
 */
std::string getStateDescription(const Int& value);

// Type conversion helpers

/**
 * @brief Convert from Int to signed 64-bit integer
 * @param value The value to convert
 * @return Integer value (throws an exception if out of range)
 */
int64_t toInt64(const Int& value);

/**
 * @brief Convert from Int to unsigned 64-bit integer
 * @param value The value to convert
 * @return Unsigned integer value (throws an exception if out of range)
 */
uint64_t toUInt64(const Int& value);

/**
 * @brief Convert from Int to double-precision floating-point number
 * @param value The value to convert
 * @return Floating-point value (precision loss is possible)
 */
double toDouble(const Int& value);

/**
 * @brief Get detailed information about the special state
 * @param value The target value
 * @return State information of type NumericState
 */
NumericState getNumericState(const Int& value);

/**
 * @brief Get detailed information about the special state (divergence details)
 * @param value The target value
 * @return Divergence detail information of type DivergenceDetail (when applicable)
 */
DivergenceDetail getDivergenceDetail(const Int& value);

/**
 * @brief Set the options for handling state errors
 * @param options State error handling options
 */
void setStateErrorOptions(const StateErrorOptions& options);

/**
 * @brief Get the current state error handling options
 * @return The current state error handling options
 */
StateErrorOptions getStateErrorOptions();

// Convergence evaluation functions

/**
     * @brief Threshold for convergence judgment
     * The difference threshold used when judging whether a result has converged in iterative computations
     */
namespace convergence_detail {
    // Hidden for internal implementation use
    inline Int convergence_threshold = Int(1);
    inline size_t max_iterations = 1000;
}

/**
 * @brief Set the convergence threshold
 * @param threshold The threshold used for convergence judgment
 */
inline void setConvergenceThreshold(const Int& threshold) {
    convergence_detail::convergence_threshold = threshold;
}

/**
 * @brief Set the maximum number of iterations
 * @param maxIterations The maximum number of iterations
 */
inline void setMaxIterations(size_t maxIterations) {
    convergence_detail::max_iterations = maxIterations;
}

/**
 * @brief Get the current convergence threshold
 * @return The currently configured convergence threshold
 */
inline Int getConvergenceThreshold() {
    return convergence_detail::convergence_threshold;
}

/**
 * @brief Get the current maximum number of iterations
 * @return The currently configured maximum number of iterations
 */
inline size_t getMaxIterations() {
    return convergence_detail::max_iterations;
}

/**
 * @brief Judge whether the value is smaller than the convergence threshold
 * @param value The value to test
 * @return true if smaller than the convergence threshold
 */
inline bool isConverged(const Int& value) {
    return abs(value) < convergence_detail::convergence_threshold;
}

/**
 * @brief Enum representing the convergence state
 */
enum class ConvergenceState {
    Converged,           // Converged
    Diverging,           // Diverging
    MaxIterationsReached, // Maximum number of iterations reached
    Oscillating,         // Oscillating
    Unknown              // State unknown
};

} // namespace sangi

// --- std::formatter specialization ---
#if __has_include(<format>)
#include <format>
#if defined(__cpp_lib_format) && __cpp_lib_format >= 202106L

template<>
struct std::formatter<sangi::Int> {
    int base_ = 10;
    bool uppercase_ = false;
    bool showBase_ = false;
    bool showSign_ = false;

    constexpr auto parse(std::format_parse_context& ctx) {
        auto it = ctx.begin();
        auto end = ctx.end();
        while (it != end && *it != '}') {
            switch (*it) {
                case 'd': base_ = 10; break;
                case 'x': base_ = 16; break;
                case 'X': base_ = 16; uppercase_ = true; break;
                case 'b': base_ = 2; break;
                case 'o': base_ = 8; break;
                case '#': showBase_ = true; break;
                case '+': showSign_ = true; break;
                default: throw std::format_error("invalid format spec for Int");
            }
            ++it;
        }
        return it;
    }

    auto format(const sangi::Int& val, std::format_context& ctx) const {
        sangi::FormatOptions opts;
        opts.base = base_;
        opts.uppercase = uppercase_;
        opts.showBase = showBase_;
        opts.showSign = showSign_;
        return std::format_to(ctx.out(), "{}", sangi::IntIOUtils::format(val, opts));
    }
};

#endif // __cpp_lib_format
#endif // __has_include(<format>)

#endif // SANGI_INT_HPP