// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// example_doc_concepts_samples.cpp
// Verification harness for samples in api/Concepts.html (ja+en).

#include <math/concepts/algebraic_concepts.hpp>
#include <math/core/mp/Rational.hpp>
#include <math/core/Complex.hpp>
#include <math/core/Quaternion.hpp>
#include <math/core/vector.hpp>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <tuple>
#include <vector>

using namespace sangi;
using namespace sangi::concepts;

// ---- doc snippets, verbatim ----------------------------------------
template<Field T>
T safe_inverse(const T& x) {
    if (x == T(0)) return T(0);
    return T(1) / x;
}

template<typename V, typename S>
    requires VectorSpace<V, S>
V linear_combination(S a, const V& v, S b, const V& w) {
    return a * v + b * w;
}

template<Ring T>
T horner(const std::vector<T>& coeffs, const T& x) {
    T result = T{0};
    for (auto it = coeffs.rbegin(); it != coeffs.rend(); ++it) {
        result = result * x + *it;
    }
    return result;
}

template<typename T>
    requires QuaternionType<T> && DivisionRing<T>
auto rotation_axis(const T& q) {
    auto v_norm = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
    return std::make_tuple(q.x / v_norm, q.y / v_norm, q.z / v_norm);
}

template<OrderedField T>
T clamp_sample(const T& x, const T& lo, const T& hi) {
    if (x < lo) return lo;
    if (x > hi) return hi;
    return x;
}

template<Field T>
T midpoint(const T& a, const T& b) {
    return (a + b) / T(2);
}

int main() {
    std::cout << std::setprecision(15);

    // ---- safe_inverse ----------------------------------------------
    {
        std::cout << "[safe_inverse]\n";
        auto inv_d = safe_inverse(3.14);
        auto inv_r = safe_inverse(Rational(3, 7));
        std::cout << "  safe_inverse(3.14)        = " << inv_d << "\n";
        std::cout << "  safe_inverse(Rational(3/7)) = " << inv_r.toString() << "\n";
        std::cout << "  safe_inverse(0.0)         = " << safe_inverse(0.0) << "  (zero guard)\n";
    }

    // ---- linear_combination ---------------------------------------
    {
        std::cout << "[linear_combination]\n";
        Vector<double> v({1.0, 2.0, 3.0});
        Vector<double> w({4.0, 5.0, 6.0});
        Vector<double> r = linear_combination<Vector<double>, double>(2.0, v, 3.0, w);
        std::cout << "  2*v+3*w = {" << r[0] << "," << r[1] << "," << r[2] << "}\n";
    }

    // ---- horner ----------------------------------------------------
    {
        std::cout << "[horner]\n";
        std::vector<double> poly = {1.0, -2.0, 3.0};  // 3x^2 - 2x + 1
        double val = horner(poly, 2.0);
        std::cout << "  horner({1,-2,3}, x=2) = " << val << "   (expected 9)\n";
    }

    // ---- rotation_axis --------------------------------------------
    {
        std::cout << "[rotation_axis]\n";
        // Around axis (1,2,2), norm = 3
        Quaternion<double> q(0.0, 1.0, 2.0, 2.0);
        auto [ax, ay, az] = rotation_axis(q);
        std::cout << "  axis = (" << ax << "," << ay << "," << az << ")\n";
        std::cout << "  |axis| = " << std::sqrt(ax*ax + ay*ay + az*az) << "  (expected 1)\n";
    }

    // ---- clamp / midpoint -----------------------------------------
    {
        std::cout << "[clamp/midpoint]\n";
        std::cout << "  clamp(2.5, 0, 1)        = " << clamp_sample(2.5, 0.0, 1.0) << "\n";
        std::cout << "  clamp(-0.3, 0, 1)       = " << clamp_sample(-0.3, 0.0, 1.0) << "\n";
        std::cout << "  midpoint(1.0, 5.0)      = " << midpoint(1.0, 5.0) << "\n";
        auto c = midpoint(Complex<double>(1.0, 0.0), Complex<double>(3.0, 4.0));
        std::cout << "  midpoint(1, 3+4i)       = " << c.re << "+" << c.im << "i\n";
    }

    // ---- concept compile-time checks (static_assert) --------------
    {
        std::cout << "[static_assert sanity]\n";
        static_assert(Field<double>);
        static_assert(Field<Rational>);
        static_assert(Field<Complex<double>>);
        static_assert(OrderedField<double>);
        static_assert(!OrderedField<Complex<double>>);
        static_assert(Ring<int>);
        static_assert(DivisionRing<Quaternion<double>>);
        static_assert(QuaternionType<Quaternion<double>>);
        std::cout << "  all concept static_asserts compiled OK\n";
    }

    return 0;
}
