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

// IntIO.hpp
// Defines I/O operations for the multi-precision integer

#ifndef SANGI_INT_IO_HPP
#define SANGI_INT_IO_HPP

#include <math/core/mp/Int/IntBase.hpp>
#include <string>
#include <span>
#include <vector>
#include <cstring>

namespace sangi {

    /**
     * @brief Integer formatting options
     */
    struct FormatOptions {
        int base = 10;         ///< Base (2-36)
        bool showSign = false; ///< Also display the sign for positive values
        bool showBase = false; ///< Display the base prefix (e.g. 0x, 0b, 0)
        bool uppercase = false; ///< Use uppercase letters for hexadecimal and similar bases
        int width = 0;         ///< Minimum width (0 = unlimited)
        bool zeroPad = false;  ///< Zero-pad (when width is set)
    };

    /**
     * @brief I/O utility class for multi-precision integers
     *
     * Provides I/O-related utility methods such as string conversion for the Int class.
     */
    class SANGI_API IntIOUtils {
    public:
        /**
         * @brief Convert a word array to a hexadecimal string
         * @param words word array
         * @param sign sign
         * @return hexadecimal string
         */
        static std::string fromRawWords(const std::vector<uint64_t>& words, int sign);

        /**
         * @brief Convert an integer to a string
         * @param value integer to convert
         * @param base base (2-36)
         * @return string representation
         */
        static std::string toString(const Int& value, int base = 10);

        /**
         * @brief Convert a string to an integer
         * @param str string to convert
         * @param base base (0 = auto-detect, 2-36)
         * @return integer value
         */
        static Int fromString(std::string_view str, int base = 0);

        /**
         * @brief Convert an integer to a string using the specified format
         * @param value integer to convert
         * @param options formatting options
         * @return formatted string
         */
        static std::string format(const Int& value, const FormatOptions& options);

        /// Set the Horner/DC switching threshold for fromString (tuning knob)
        static void setFromStringDCThreshold(size_t threshold);
        static size_t getFromStringDCThreshold();

        /// Endianness selector
        enum class Endian { Little, Big, Native };

        /**
         * @brief Export an integer to a portable binary format
         *
         * Format: [sign:1 byte][size:4 bytes LE][words: size * 8 bytes]
         *   sign: 0 = zero, 1 = positive, 0xFF = negative
         *   size: number of words (4-byte LE)
         *   words: each 64-bit word (specified endianness, LSW first)
         *
         * @param value integer to export
         * @param endian byte order for the words (default Little)
         * @return binary data
         */
        static std::vector<uint8_t> exportBinary(const Int& value,
                                                  Endian endian = Endian::Little);

        /**
         * @brief Import an integer from the portable binary format
         *
         * Restores an Int from data produced by exportBinary.
         *
         * @param data binary data
         * @param endian byte order of the words (must match exportBinary)
         * @return restored integer
         * @throws std::invalid_argument when the data is malformed
         */
        static Int importBinary(std::span<const uint8_t> data,
                                Endian endian = Endian::Little);
    };

} // namespace sangi

#endif // SANGI_INT_IO_HPP
