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

// IntSpecialStates.cpp
// Implementation of special-state handling for multiprecision integers

#include <math/core/mp/Int/IntSpecialStates.hpp>
#include <sstream>

namespace sangi {

    std::string IntSpecialStates::handleToString(const Int& value, int base) {
        // Do not handle normal values
        if (value.m_state == NumericState::Normal) {
            return ""; // Return an empty string to indicate that normal conversion should be performed
        }

        // String representation of special states
        switch (value.m_state) {
        case NumericState::NaN:
            return "NaN";
        case NumericState::PositiveInfinity:
            return "Infinity";
        case NumericState::NegativeInfinity:
            return "-Infinity";
        case NumericState::PositiveZero:
            return "0";
        case NumericState::NegativeZero:
            return "-0";
        case NumericState::Overflow:
            return "Overflow";
        case NumericState::Underflow:
            return "Underflow";
        case NumericState::Interrupted:
            return "Interrupted";
        case NumericState::PrecisionLimit:
            return "PrecisionLimit";
        case NumericState::NotConverged:
            return "NotConverged";
        case NumericState::Divergent:
            return "Divergent";
        case NumericState::Oscillating:
            return "Oscillating";
        case NumericState::SlowConvergence:
            return "SlowConvergence";
        case NumericState::TruncatedConvergence:
            return "TruncatedConvergence";
        default:
            // Include error information
            if (value.m_error != NumericError::None) {
                std::stringstream ss;
                ss << "Error(" << static_cast<int>(value.m_error) << ")";
                return ss.str();
            }
            return "UnknownState";
        }
    }

    Int IntSpecialStates::handleAddition(const Int& lhs, const Int& rhs) {
        // If either is NaN, return NaN
        if (lhs.isNaN() || rhs.isNaN()) {
            return Int::NaN();
        }

        // Addition of infinities
        if (lhs.m_state == NumericState::PositiveInfinity) {
            if (rhs.m_state == NumericState::NegativeInfinity) {
                // +∞ + (-∞) = NaN
                Int result = Int::NaN();
                result.m_error = NumericError::InfiniteIndeterminate;
                return result;
            }
            // +∞ + x = +∞ (x is a finite value or +∞)
            return Int::PositiveInfinity();
        }
        if (lhs.m_state == NumericState::NegativeInfinity) {
            if (rhs.m_state == NumericState::PositiveInfinity) {
                // -∞ + (+∞) = NaN
                Int result = Int::NaN();
                result.m_error = NumericError::InfiniteIndeterminate;
                return result;
            }
            // -∞ + x = -∞ (x is a finite value or -∞)
            return Int::NegativeInfinity();
        }
        if (rhs.m_state == NumericState::PositiveInfinity) {
            // x + (+∞) = +∞ (x is a finite value)
            return Int::PositiveInfinity();
        }
        if (rhs.m_state == NumericState::NegativeInfinity) {
            // x + (-∞) = -∞ (x is a finite value)
            return Int::NegativeInfinity();
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // Overflow, etc.
            Int result = Int::NaN();
            result.m_error = NumericError::None;
            return result;
        }

        // This should be unreachable (addition of normal values is handled separately)
        return Int::NaN();
    }

    Int IntSpecialStates::handleSubtraction(const Int& lhs, const Int& rhs) {
        // If either is NaN, return NaN
        if (lhs.isNaN() || rhs.isNaN()) {
            return Int::NaN();
        }

        // Subtraction of infinities
        if (lhs.m_state == NumericState::PositiveInfinity) {
            if (rhs.m_state == NumericState::PositiveInfinity) {
                // +∞ - (+∞) = NaN
                Int result = Int::NaN();
                result.m_error = NumericError::InfiniteIndeterminate;
                return result;
            }
            // +∞ - x = +∞ (x is a finite value or -∞)
            return Int::PositiveInfinity();
        }
        if (lhs.m_state == NumericState::NegativeInfinity) {
            if (rhs.m_state == NumericState::NegativeInfinity) {
                // -∞ - (-∞) = NaN
                Int result = Int::NaN();
                result.m_error = NumericError::InfiniteIndeterminate;
                return result;
            }
            // -∞ - x = -∞ (x is a finite value or +∞)
            return Int::NegativeInfinity();
        }
        if (rhs.m_state == NumericState::PositiveInfinity) {
            // x - (+∞) = -∞ (x is a finite value)
            return Int::NegativeInfinity();
        }
        if (rhs.m_state == NumericState::NegativeInfinity) {
            // x - (-∞) = +∞ (x is a finite value)
            return Int::PositiveInfinity();
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // Overflow, etc.
            Int result = Int::NaN();
            result.m_error = NumericError::None;
            return result;
        }

        // This should be unreachable (subtraction of normal values is handled separately)
        return Int::NaN();
    }

    Int IntSpecialStates::handleMultiplication(const Int& lhs, const Int& rhs) {
        // If either is NaN, return NaN
        if (lhs.isNaN() || rhs.isNaN()) {
            return Int::NaN();
        }

        // Multiplication by zero
        if (lhs.m_sign == 0 || rhs.m_sign == 0) {
            // 0 * ∞ = NaN (undefined)
            if (lhs.isInfinite() || rhs.isInfinite()) {
                Int result = Int::NaN();
                result.m_error = NumericError::ZeroTimesInfinity;
                return result;
            }
            // 0 * x = 0 (x is a finite value)
            return Int::Zero();
        }

        // Multiplication with infinity
        if (lhs.isInfinite() || rhs.isInfinite()) {
            // Determine the sign
            int resultSign = lhs.m_sign * rhs.m_sign;
            // Set the result
            if (resultSign > 0) {
                return Int::PositiveInfinity();
            }
            else {
                return Int::NegativeInfinity();
            }
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // Overflow, etc.
            Int result = Int::NaN();
            result.m_error = NumericError::None;
            return result;
        }

        // This should be unreachable (multiplication of normal values is handled separately)
        return Int::NaN();
    }

    Int IntSpecialStates::handleDivision(const Int& lhs, const Int& rhs) {
        // If either is NaN, return NaN
        if (lhs.isNaN() || rhs.isNaN()) {
            return Int::NaN();
        }

        // Division by zero
        if (rhs.m_sign == 0) {
            if (lhs.m_sign == 0) {
                // 0 / 0 = NaN (undefined)
                Int result = Int::NaN();
                result.m_error = NumericError::DivideByZero;
                return result;
            }
            // x / 0 = ±∞ (depends on the sign of x)
            if (lhs.m_sign < 0) {
                return Int::NegativeInfinity();
            }
            else {
                return Int::PositiveInfinity();
            }
        }

        // Handling of infinity
        if (lhs.isInfinite()) {
            if (rhs.isInfinite()) {
                // ∞ / ∞ = NaN (undefined)
                Int result = Int::NaN();
                result.m_error = NumericError::InfiniteIndeterminate;
                return result;
            }
            // ∞ / x = ±∞ (depends on the sign)
            int resultSign = lhs.m_sign * rhs.m_sign;
            if (resultSign > 0) {
                return Int::PositiveInfinity();
            }
            else {
                return Int::NegativeInfinity();
            }
        }

        // Dividing a finite value by infinity
        if (rhs.isInfinite()) {
            // x / ∞ = 0 (x is a finite value)
            return Int::Zero();
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // Overflow, etc.
            Int result = Int::NaN();
            result.m_error = NumericError::None;
            return result;
        }

        // This should be unreachable (division of normal values is handled separately)
        return Int::NaN();
    }

    Int IntSpecialStates::handleModulo(const Int& lhs, const Int& rhs) {
        // If either is NaN, return NaN
        if (lhs.isNaN() || rhs.isNaN()) {
            return Int::NaN();
        }

        // Modulo by zero
        if (rhs.m_sign == 0) {
            // x % 0 = NaN (undefined)
            Int result = Int::NaN();
            result.m_error = NumericError::DivideByZero;
            return result;
        }

        // Handling of infinity
        if (lhs.isInfinite()) {
            // ∞ % x = NaN (undefined)
            Int result = Int::NaN();
            result.m_error = NumericError::InfiniteIndeterminate;
            return result;
        }

        // Modulo of a finite value divided by infinity
        if (rhs.isInfinite()) {
            // x % ∞ = x (x is a finite value)
            return lhs;
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // Overflow, etc.
            Int result = Int::NaN();
            result.m_error = NumericError::None;
            return result;
        }

        // This should be unreachable (modulo of normal values is handled separately)
        return Int::NaN();
    }

    bool IntSpecialStates::compareLessThan(const Int& lhs, const Int& rhs) {
        // If either is NaN, always false
        if (lhs.isNaN() || rhs.isNaN()) {
            return false;
        }

        // Comparison of infinities
        if (lhs.m_state == NumericState::NegativeInfinity) {
            return rhs.m_state != NumericState::NegativeInfinity; // -∞ < x (x ≠ -∞)
        }
        if (rhs.m_state == NumericState::PositiveInfinity) {
            return lhs.m_state != NumericState::PositiveInfinity; // x < +∞ (x ≠ +∞)
        }
        if (lhs.m_state == NumericState::PositiveInfinity) {
            return false; // +∞ < x is always false
        }
        if (rhs.m_state == NumericState::NegativeInfinity) {
            return false; // x < -∞ is always false
        }

        // Other special states
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            // The ordering of special states is not defined
            return false;
        }

        // This should be unreachable (comparison of normal values is handled separately)
        return false;
    }

    bool IntSpecialStates::compareEqual(const Int& lhs, const Int& rhs) {
        // If either is NaN, always false
        if (lhs.isNaN() || rhs.isNaN()) {
            return false;
        }

        // Equal if both are in the same special state
        if (lhs.m_state != NumericState::Normal && lhs.m_state == rhs.m_state) {
            // For infinity, also consider the sign
            if (lhs.isInfinite()) {
                return lhs.m_sign == rhs.m_sign;
            }
            return true;
        }

        // Different special states, or a special state vs. a normal value, are not equal
        if (lhs.m_state != NumericState::Normal || rhs.m_state != NumericState::Normal) {
            return false;
        }

        // This should be unreachable (comparison of normal values is handled separately)
        return false;
    }

} // namespace sangi