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

// numeric_state.hpp
// 数値状態管理システム
//
// このファイルでは、多倍長整数や浮動小数点数などの数値型で
// 共通して使用される状態管理システムを定義します。
// IEEE 754の特殊値や数値計算における様々な状態を表現します。

#ifndef CALX_NUMERIC_STATE_HPP
#define CALX_NUMERIC_STATE_HPP

#include <math/core/basic_types.hpp>
#include <string>
#include <type_traits>
#include <concepts>

namespace calx {

    /**
     * @brief 数値状態の特性に関するクラス
     *
     * このクラスは、数値状態の分類や特性を判定するためのメソッドを提供します。
     */
    class NumericStateTraits {
    public:
        /**
         * @brief 状態がNaNかどうかを判定
         * @param state 判定する状態
         * @return NaNである場合はtrue
         */
        static constexpr bool isNaN(NumericState state) {
            return state == NumericState::NaN;
        }

        /**
         * @brief 状態が無限大かどうかを判定
         * @param state 判定する状態
         * @return 無限大である場合はtrue
         */
        static constexpr bool isInfinite(NumericState state) {
            return state == NumericState::PositiveInfinity ||
                state == NumericState::NegativeInfinity ||
                state == NumericState::ComplexInfinity;
        }

        /**
         * @brief 状態が収束していないかどうかを判定
         * @param state 判定する状態
         * @return 収束していない場合はtrue
         */
        static constexpr bool isNotConverged(NumericState state) {
            return state == NumericState::NotConverged;
        }

        /**
         * @brief 状態が発散しているかどうかを判定
         * @param state 判定する状態
         * @return 発散している場合はtrue
         */
        static constexpr bool isDivergent(NumericState state) {
            return state == NumericState::Divergent ||
                state == NumericState::NotConverged ||
                state == NumericState::Oscillating ||
                state == NumericState::SlowConvergence;
        }

        /**
         * @brief 状態が特殊状態かどうかを判定
         * @param state 判定する状態
         * @return 特殊状態である場合はtrue（正常以外）
         */
        static constexpr bool isSpecial(NumericState state) {
            return state != NumericState::Normal;
        }

        /**
         * @brief 状態の文字列表現を取得
         * @param state 状態
         * @return 状態の文字列表現
         */
        static std::string toString(NumericState state) {
            switch (state) {
            case NumericState::Normal: return "Normal";
            case NumericState::NaN: return "NaN";
            case NumericState::PositiveInfinity: return "Infinity";
            case NumericState::NegativeInfinity: return "-Infinity";
            case NumericState::ComplexInfinity: return "ComplexInfinity";
            case NumericState::Overflow: return "Overflow";
            case NumericState::Underflow: return "Underflow";
            case NumericState::Interrupted: return "Interrupted";
            case NumericState::PrecisionLimit: return "PrecisionLimit";
            case NumericState::PositiveZero: return "+Zero";
            case NumericState::NegativeZero: return "-Zero";
            case NumericState::Subnormal: return "Subnormal";
            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: return "Unknown";
            }
        }

        /**
         * @brief 符号の文字列表現を取得
         * @param sign 符号
         * @return 符号の文字列表現
         */
        static std::string toString(int sign) {
            if (sign < 0) return "負";
            else if (sign > 0) return "正";
            else return "零";
        }

        /**
         * @brief 発散詳細の文字列表現を取得
         * @param detail 発散詳細
         * @return 発散詳細の文字列表現
         */
        static std::string toString(DivergenceDetail detail) {
            switch (detail) {
            case DivergenceDetail::None: return "None";
            case DivergenceDetail::Diverging: return "Diverging";
            case DivergenceDetail::Oscillating: return "Oscillating";
            case DivergenceDetail::Chaotic: return "Chaotic";
            case DivergenceDetail::SlowConvergence: return "SlowConvergence";
            case DivergenceDetail::TruncatedConvergence: return "TruncatedConvergence";
            case DivergenceDetail::ConditionalConvergenceViolation: return "ConditionalConvergenceViolation";
            case DivergenceDetail::AlternatingSeriesDivergence: return "AlternatingSeriesDivergence";
            default: return "Unknown";
            }
        }


        /**
         * @brief エラー原因の文字列表現を取得
         * @param error エラー原因
         * @return エラー原因の文字列表現
         */
        static std::string toString(NumericError error) {
            switch (error) {
            case NumericError::None: return "None";
            case NumericError::DivideByZero: return "DivideByZero";
            case NumericError::InfiniteIndeterminate: return "InfiniteIndeterminate";
            case NumericError::ZeroTimesInfinity: return "ZeroTimesInfinity";
            case NumericError::NegativeSqrt: return "NegativeSqrt";
            case NumericError::ConversionError: return "ConversionError";
            case NumericError::ExplicitNaN: return "ExplicitNaN";
            case NumericError::Uninitialized: return "Uninitialized";
            case NumericError::InvalidBitPattern: return "InvalidBitPattern";
            case NumericError::InvalidStringConversion: return "InvalidStringConversion";
            case NumericError::OutOfRangeInput: return "OutOfRangeInput";
            case NumericError::NaNPropagation: return "NaNPropagation";
            case NumericError::IntegerConversionError: return "IntegerConversionError";
            case NumericError::FunctionDomainError: return "FunctionDomainError";
            case NumericError::InvalidBitOperation: return "InvalidBitOperation";
            case NumericError::DivergenceError: return "DivergenceError";
            default: return "Unknown";
            }
        }


        /**
         * @brief エラー原因から状態を決定
         * @param error エラー原因
         * @return 対応する状態
         */
        static NumericState errorToState(NumericError error) {
            switch (error) {
            case NumericError::None:
                return NumericState::Normal;
            case NumericError::DivideByZero:
                return NumericState::NaN; // 0/0の場合
                // 注意: n/0の場合は符号に応じてPositiveInfinityまたはNegativeInfinityになる
            case NumericError::InfiniteIndeterminate:
            case NumericError::ZeroTimesInfinity:
            case NumericError::NegativeSqrt:
            case NumericError::ExplicitNaN:
            case NumericError::Uninitialized:
            case NumericError::InvalidBitPattern:
            case NumericError::InvalidStringConversion:
            case NumericError::NaNPropagation:
            case NumericError::FunctionDomainError:
            case NumericError::InvalidBitOperation:
                return NumericState::NaN;
            case NumericError::ConversionError:
            case NumericError::OutOfRangeInput:
            case NumericError::IntegerConversionError:
                return NumericState::Overflow;
            case NumericError::DivergenceError:
                return NumericState::Divergent;
            default:
                return NumericState::NaN;
            }
        }


        /**
         * @brief 状態からデフォルトのエラー原因を推定
         * @param state 状態
         * @return 推定されるエラー原因
         * @note 1対1のマッピングではないため、完全な逆変換ではない
         */
        static NumericError stateToDefaultError(NumericState state) {
            switch (state) {
            case NumericState::Normal:
            case NumericState::PositiveZero:
            case NumericState::NegativeZero:
                return NumericError::None;
            case NumericState::NaN:
                return NumericError::ExplicitNaN;
            case NumericState::PositiveInfinity:
            case NumericState::NegativeInfinity:
            case NumericState::ComplexInfinity:
                // デフォルトは不明な無限大
                return NumericError::InfiniteIndeterminate;
            case NumericState::Overflow:
                return NumericError::OutOfRangeInput;
            case NumericState::Underflow:
                return NumericError::OutOfRangeInput;
            case NumericState::Interrupted:
                return NumericError::None;
            case NumericState::PrecisionLimit:
                return NumericError::None;
            case NumericState::Subnormal:
                return NumericError::None;
            case NumericState::NotConverged:
            case NumericState::Divergent:
            case NumericState::Oscillating:
            case NumericState::SlowConvergence:
                return NumericError::DivergenceError;
            default:
                return NumericError::None;
            }
        }


        /**
         * @brief 状態がエラーコードを必要とするかどうかを判定
         * @param state 判定する状態
         * @return エラーコードが必要な場合はtrue
         */
        static bool requiresErrorCode(NumericState state) {
            return state != NumericState::Normal &&
                state != NumericState::PositiveZero &&
                state != NumericState::NegativeZero;
        }

    };

    /**
     * @brief 数値状態の特性を提供するテンプレートクラス
     *
     * このテンプレートは数値型ごとに特殊化され、その型の状態管理機能を提供します。
     * 代数系コンセプトとは独立した層として機能します。
     */
    template<typename T>
    struct numeric_state_traits {
        // デフォルトでは未サポート
        static constexpr bool is_supported = false;

        // このままでは使用できないダミーメソッド
        static bool isNormal(const T&) { return true; }
        static bool isNaN(const T&) { return false; }
        static bool isInfinite(const T&) { return false; }
        static bool isNotConverged(const T&) { return false; }
        static NumericState getState(const T&) { return NumericState::Normal; }
        static NumericError getError(const T&) { return NumericError::None; }
        static int getSign(const T&) { return 0; }
    };

    // 基本型のためのヘルパー関数

    /**
     * @brief 符号を取得
     * @param value 値
     * @return 符号
     */
    template<std::integral T>
    constexpr int getSign(T value) {
        return value < 0 ? -1 :
            value > 0 ? 1 : 0;
    }

    template<std::floating_point T>
    constexpr int getSign(T value) {
        return value < 0 ? -1 :
            value > 0 ? 1 : 0;
    }

    /**
     * @brief 符号を反転
     * @param sign 符号
     * @return 反転した符号
     */
    constexpr int negateSign(int sign) {
        return -sign;
    }

    /**
     * @brief 二つの符号から乗算/除算結果の符号を決定
     * @param a 第1符号
     * @param b 第2符号
     * @return 結果の符号
     */
    constexpr int combineSignsMultiply(int a, int b) {
        if (a == 0 || b == 0) return 0;
        return (a == b) ? 1 : -1;
    }

    /**
     * @brief 二つの符号から加算結果の符号を決定
     * @param a 第1符号
     * @param b 第2符号
     * @param absCompare 絶対値の比較結果（負数: |a|<|b|, 0: |a|=|b|, 正数: |a|>|b|）
     * @return 結果の符号
     */
    constexpr int combineSignsAdd(int a, int b, int absCompare) {
        // 符号が同じ場合、結果の符号も同じ
        if (a == b) return a;

        // 符号が異なる場合、絶対値の大きい方の符号になる
        if (absCompare < 0) return b;       // |a| < |b|
        else if (absCompare > 0) return a;  // |a| > |b|
        else return 0;                      // |a| = |b|
    }

    // 状態管理のためのコンセプト

    /**
     * @brief 状態管理をサポートする型のコンセプト
     */
    template<typename T>
    concept HasNumericState = requires(T a) {
        { numeric_state_traits<T>::isNormal(a) } -> std::convertible_to<bool>;
        { numeric_state_traits<T>::getState(a) } -> std::convertible_to<NumericState>;
        { numeric_state_traits<T>::getError(a) } -> std::convertible_to<NumericError>;
        { numeric_state_traits<T>::getSign(a) } -> std::convertible_to<int>;
    };

    /**
     * @brief 発散詳細をサポートする型のコンセプト
     */
    template<typename T>
    concept HasDivergenceHandling = requires(T a) {
        { numeric_state_traits<T>::isNotConverged(a) } -> std::convertible_to<bool>;
        { numeric_state_traits<T>::getDivergenceDetail(a) } -> std::convertible_to<DivergenceDetail>;
    };

    /**
     * @brief オーバーフロー検出をサポートする型のコンセプト
     */
    template<typename T>
    concept HasOverflowDetection = requires(T a) {
        { numeric_state_traits<T>::isOverflow(a) } -> std::convertible_to<bool>;
    };

} // namespace calx

#endif // CALX_NUMERIC_STATE_HPP