#pragma once
// euclidean_geometry.hpp
//
// Corner-angle formula for Euclidean triangles in the discrete conformal
// (log-length) parametrisation.
//
// Ported from de.varylab.discreteconformal.functional.EuclideanCyclicFunctional.
//
// In the discrete conformal parametrisation a Euclidean triangle is described by
// its three effective log-lengths Λ̃_ij = λ°_ij + u_i + u_j (+ edge DOF).
// The corresponding side lengths are l_ij = exp(Λ̃_ij / 2).
//
// Vertex ordering convention (matches EuclideanCyclicFunctional.java):
//   v1 is opposite edge l23,  v2 is opposite l31,  v3 is opposite l12.
//
// t-value trick (Springborn 2008 §3):
//   t12 = −l12 + l23 + l31  =  2(s − l12)
//   t23 = +l12 − l23 + l31  =  2(s − l23)
//   t31 = +l12 + l23 − l31  =  2(s − l31)
//   denom = sqrt(t12 · t23 · t31 · l123) = 4 · Area
//
//   α_v = 2 · atan2( product of t-values adjacent to v, denom )
//
// The centering trick (l_ij ← exp((Λ̃_ij − 2·μ)/2), μ = (Λ̃12+Λ̃23+Λ̃31)/6)
// rescales all three sides by the same factor, leaving angles unchanged but
// keeping the arguments of exp in a safe numerical range.

#include <cmath>

namespace conformallab {

struct EuclideanFaceAngles {
    double alpha1;   ///< corner angle at v1 (opposite l23)
    double alpha2;   ///< corner angle at v2 (opposite l31)
    double alpha3;   ///< corner angle at v3 (opposite l12)
    bool   valid;
};

// ── From side lengths ─────────────────────────────────────────────────────────
//
// Given three Euclidean side lengths l12, l23, l31 > 0 satisfying the triangle
// inequality, compute the corner angles.
//
// Returns valid=false if the triangle inequality is violated (any t-value ≤ 0).
inline EuclideanFaceAngles euclidean_angles_from_lengths(
    double l12, double l23, double l31)
{
    const double t12 = -l12 + l23 + l31;   // 2*(s − l12)
    const double t23 = +l12 - l23 + l31;   // 2*(s − l23)
    const double t31 = +l12 + l23 - l31;   // 2*(s − l31)

    if (t12 <= 0.0 || t23 <= 0.0 || t31 <= 0.0)
        return {0.0, 0.0, 0.0, false};

    const double l123  = l12 + l23 + l31;
    const double denom2 = t12 * t23 * t31 * l123;  // = (4·Area)²
    if (denom2 <= 0.0)
        return {0.0, 0.0, 0.0, false};

    const double denom = std::sqrt(denom2);

    // α at v1 (opposite l23): adjacent t-values are t12 and t31
    // α at v2 (opposite l31): adjacent t-values are t12 and t23
    // α at v3 (opposite l12): adjacent t-values are t23 and t31
    return {
        2.0 * std::atan2(t12 * t31, denom),
        2.0 * std::atan2(t12 * t23, denom),
        2.0 * std::atan2(t23 * t31, denom),
        true
    };
}

// ── From effective log-lengths Λ̃ ─────────────────────────────────────────────
//
// Converts to side lengths l_ij = exp(Λ̃_ij / 2), applying the centering
// trick for numerical safety, then delegates to euclidean_angles_from_lengths.
//
// The centering constant μ = (Λ̃12 + Λ̃23 + Λ̃31) / 6 ensures
//   l12 · l23 · l31 = 1  (geometric mean = 1)
// which keeps all l values near 1 and prevents float overflow for large |Λ̃|.
inline EuclideanFaceAngles euclidean_angles(
    double lam12, double lam23, double lam31)
{
    const double mu   = (lam12 + lam23 + lam31) / 6.0;
    const double l12  = std::exp((lam12 - 2.0 * mu) * 0.5);
    const double l23  = std::exp((lam23 - 2.0 * mu) * 0.5);
    const double l31  = std::exp((lam31 - 2.0 * mu) * 0.5);
    return euclidean_angles_from_lengths(l12, l23, l31);
}

} // namespace conformallab
