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

// RationalBase.hpp
// 多倍長有理数クラスの基本定義

#ifndef CALX_RATIONAL_BASE_HPP
#define CALX_RATIONAL_BASE_HPP

#include <math/core/mp/Int.hpp>
#include <string>
#include <iosfwd>
#include <vector>
#include <compare>  // C++20 三方比較演算子

namespace calx {

    // 前方宣言
    class Float;

    /**
     * @brief 多倍長有理数クラス
     *
     * 任意精度の有理数 (分子/分母) を表現するクラス。
     * 分母は常に正、分母子は常に約分済みの状態を維持する。
     * 内部で Int クラスを使用する。
     */
    class Rational {
    private:
        Int numerator_;     // 分子
        Int denominator_;   // 分母 (常に正, 約分済み)

    public:
        // --- コンストラクタ ---
        Rational();
        explicit Rational(int num, int den = 1);
        explicit Rational(const Int& num);
        Rational(const Int& num, const Int& den, bool doReduce = true);
        Rational(Int&& num, Int&& den, bool doReduce = true);
        Rational(const Rational& other);
        Rational(Rational&& other) noexcept;
        explicit Rational(std::string_view str, int base = 10);
        explicit Rational(double value);
        explicit Rational(float value);
        explicit Rational(const Float& value);

        ~Rational() = default;

        // --- アクセサ ---
        [[nodiscard]] const Int& numerator() const { return numerator_; }
        [[nodiscard]] const Int& denominator() const { return denominator_; }

        // --- 代入 ---
        Rational& operator=(const Rational& other);
        Rational& operator=(Rational&& other) noexcept;
        Rational& operator=(int value);
        Rational& operator=(double value);
        Rational& operator=(float value);
        Rational& operator=(const Int& value);

        // --- 比較演算子 ---
        friend std::partial_ordering operator<=>(const Rational& lhs, const Rational& rhs);
        friend bool operator==(const Rational& lhs, const Rational& rhs);
        friend std::partial_ordering operator<=>(const Rational& lhs, const Int& rhs);
        friend bool operator==(const Rational& lhs, const Int& rhs);
        friend std::partial_ordering operator<=>(const Rational& lhs, int rhs);
        friend bool operator==(const Rational& lhs, int rhs);

        // --- 単項演算子 ---
        const Rational& operator+() const& { return *this; }
        Rational&& operator+() && { return std::move(*this); }
        [[nodiscard]] Rational operator-() const&;
        [[nodiscard]] Rational operator-() &&;

        // --- インクリメント/デクリメント ---
        Rational& operator++();
        [[nodiscard]] Rational operator++(int);
        Rational& operator--();
        [[nodiscard]] Rational operator--(int);

        // --- 四則演算 (Rational <-> Rational) ---
        friend Rational operator+(const Rational& lhs, const Rational& rhs);
        friend Rational operator-(const Rational& lhs, const Rational& rhs);
        friend Rational operator*(const Rational& lhs, const Rational& rhs);
        friend Rational operator/(const Rational& lhs, const Rational& rhs);
        friend Rational operator%(const Rational& lhs, const Rational& rhs);

        // --- 四則演算 (Rational <-> Int) ---
        friend Rational operator+(const Rational& lhs, const Int& rhs);
        friend Rational operator+(const Int& lhs, const Rational& rhs);
        friend Rational operator-(const Rational& lhs, const Int& rhs);
        friend Rational operator-(const Int& lhs, const Rational& rhs);
        friend Rational operator*(const Rational& lhs, const Int& rhs);
        friend Rational operator*(const Int& lhs, const Rational& rhs);
        friend Rational operator/(const Rational& lhs, const Int& rhs);
        friend Rational operator/(const Int& lhs, const Rational& rhs);

        // --- 四則演算 (Rational <-> int) ---
        friend Rational operator+(const Rational& lhs, int rhs);
        friend Rational operator+(int lhs, const Rational& rhs);
        friend Rational operator-(const Rational& lhs, int rhs);
        friend Rational operator-(int lhs, const Rational& rhs);
        friend Rational operator*(const Rational& lhs, int rhs);
        friend Rational operator*(int lhs, const Rational& rhs);
        friend Rational operator/(const Rational& lhs, int rhs);
        friend Rational operator/(int lhs, const Rational& rhs);

        // --- 複合代入 ---
        Rational& operator+=(const Rational& rhs);
        Rational& operator-=(const Rational& rhs);
        Rational& operator*=(const Rational& rhs);
        Rational& operator/=(const Rational& rhs);
        Rational& operator+=(const Int& rhs);
        Rational& operator-=(const Int& rhs);
        Rational& operator*=(const Int& rhs);
        Rational& operator/=(const Int& rhs);
        Rational& operator+=(int rhs);
        Rational& operator-=(int rhs);
        Rational& operator*=(int rhs);
        Rational& operator/=(int rhs);

        // --- 冪乗 ---
        [[nodiscard]] Rational pow(int exponent) const;

        // --- シフト (2の冪による乗除) ---
        [[nodiscard]] Rational operator<<(int n) const;
        [[nodiscard]] Rational operator>>(int n) const;

        // --- 状態判定 ---
        [[nodiscard]] bool isNegative() const { return numerator_.isNegative(); }
        [[nodiscard]] bool isNonPositive() const { return numerator_.isNegative() || numerator_.isZero(); }
        [[nodiscard]] bool isZero() const { return numerator_.isZero() && denominator_.isNormal(); }
        [[nodiscard]] bool isNonZero() const { return !isZero(); }
        [[nodiscard]] bool isNonNegative() const { return !numerator_.isNegative(); }
        [[nodiscard]] bool isPositive() const { return numerator_.isPositive(); }
        [[nodiscard]] bool isOne() const { return numerator_ == denominator_ && denominator_.isNormal(); }
        [[nodiscard]] bool isInteger() const { return !isNaN() && denominator_.isOne(); }
        [[nodiscard]] bool isNaN() const { return numerator_.isNaN() || denominator_.isNaN(); }

        // --- 便利関数 ---
        [[nodiscard]] Rational doubled() const;
        [[nodiscard]] Rational halved() const;

        /// 逆数を返す (分子と分母をスワップ)。O(1)。
        /// ゼロの逆数は NaN (分母=0) を返す。
        [[nodiscard]] Rational reciprocal() const {
            if (isZero() || isNaN()) return Rational(Int(0), Int(0), false);
            // 符号を分子に保持: 分母が負なら符号反転
            if (numerator_.isNegative()) {
                return Rational(-denominator_, -numerator_, false);
            }
            return Rational(denominator_, numerator_, false);
        }

        // --- swap ---
        friend void swap(Rational& a, Rational& b) noexcept;

        // --- 約分 ---
        bool reduce();

        // --- 変換 ---
        explicit operator int() const;
        explicit operator float() const;
        explicit operator double() const;
        [[nodiscard]] double toDouble() const;
        [[nodiscard]] float toFloat() const;
        [[nodiscard]] Float toMpFloat(int precision = 0) const;
        [[nodiscard]] std::string toString(int base = 10) const;
        [[nodiscard]] std::string toDecimal(int digits = 20) const;

        // --- 連分数 ---
        [[nodiscard]] std::vector<Int> toContinuedFraction() const;
        [[nodiscard]] static Rational fromContinuedFraction(const std::vector<Int>& cf);

        // --- ストリーム ---
        friend std::ostream& operator<<(std::ostream& os, const Rational& r);
        friend std::istream& operator>>(std::istream& is, Rational& r);
    };

    // --- フリー関数 ---
    [[nodiscard]] Rational abs(const Rational& x);
    [[nodiscard]] Int floor(const Rational& x);
    [[nodiscard]] Int ceil(const Rational& x);
    [[nodiscard]] Int trunc(const Rational& x);
    [[nodiscard]] Int round(const Rational& x);
    [[nodiscard]] Rational square(const Rational& x);
    [[nodiscard]] Int height(const Rational& x);
    [[nodiscard]] Rational conj(const Rational& x);
    [[nodiscard]] Rational gcd(const Rational& x, const Rational& y);

    // --- ユーティリティ関数 ---
    [[nodiscard]] Rational inv(const Rational& x);
    [[nodiscard]] int sgn(const Rational& x);
    [[nodiscard]] Rational frac(const Rational& x);
    [[nodiscard]] Rational mediant(const Rational& a, const Rational& b);

    // --- 有理数復元 (FLINT-23) ---
    // a mod m から p/q (|p| ≤ N, 0 < q ≤ D) を復元
    [[nodiscard]] Rational reconstructRational(const Int& a, const Int& m,
                                               const Int& N, const Int& D);

    // --- 調和数 (FLINT-24) ---
    // H_n = 1 + 1/2 + ... + 1/n (正確な有理数)
    [[nodiscard]] Rational harmonicNumber(unsigned int n);

    // --- デデキント和 (FLINT-25) ---
    // s(h,k) = Σ_{i=1}^{k-1} ((i/k))((hi/k))
    [[nodiscard]] Rational dedekindSum(const Int& h, const Int& k);

    // --- 有理数列挙 (FLINT-26) ---
    // Stern-Brocot 順 (高さ昇順) で次の正有理数
    [[nodiscard]] Rational nextMinimal(const Rational& x);
    // Calkin-Wilf 列で次の正有理数
    [[nodiscard]] Rational nextCalkinWilf(const Rational& x);

    // --- ファレイ近傍 (FLINT-27) ---
    // Farey 数列 F_Q における左右近傍 (left, right)
    [[nodiscard]] std::pair<Rational, Rational> fareyNeighbors(
        const Rational& x, const Int& Q);
    // 開区間 (a, b) 内の最小高さ有理数
    [[nodiscard]] Rational simplestBetween(const Rational& a, const Rational& b);

    // --- 有理数の mod (FLINT-29) ---
    // (p/q) mod m = p * q^{-1} mod m (q と m は互いに素)
    [[nodiscard]] Int mod(const Rational& x, const Int& m);

    // --- 大指数冪乗 (FLINT-30) ---
    // 指数が Int (多倍長) の冪乗
    [[nodiscard]] Rational pow(const Rational& x, const Int& exponent);

} // namespace calx

#endif // CALX_RATIONAL_BASE_HPP
