#include <numbers>

using std::numbers::pi;

#include "Sample/HardParticle/HardParticles.h"
#include "Tests/GTestWrapper/google_test.h"
#include "Tests/Unit/Numeric/MultiQTest.h"
#include <ff/Face.h> // for diagnostic

//! Check that form factors are invariant when q is transformed according to particle symmetry.

class FFSymmetryTest : public testing::Test {
protected:
    void run_test(Formfactor* ff, std::function<C3(const C3&)> trafo, double eps, double qmag1,
                  double qmag2)
    {
        int failures = formfactorTest::run_test_for_many_q(
            [&](C3 q) -> complex_t { return ff->formfactorAtBottom(q); },
            [&](C3 q) -> complex_t { return ff->formfactorAtBottom(trafo(q)); }, qmag1, qmag2, eps);
        EXPECT_EQ(failures, 0);
    }
};

//*********** spheroids ***************

TEST_F(FFSymmetryTest, Ellipsoid)
{
    Ellipsoid ff(.53, .78, 1.3);
    run_test(&ff, [](const C3& q) -> C3 { return C3(-q.x(), q.y(), q.z()); }, 1e-12, 1e-99, 2e2);
    run_test(&ff, [](const C3& q) -> C3 { return C3(q.x(), -q.y(), q.z()); }, 1e-12, 1e-99, 2e2);
}

TEST_F(FFSymmetryTest, EllipsoidalSegment)
{
    EllipsoidalSegment ff(.79, .89, .65, 0.1, 0.3);
    run_test(&ff, [](const C3& q) -> C3 { return C3(-q.x(), q.y(), q.z()); }, 1e-12, 1e-99, 2e2);
    run_test(&ff, [](const C3& q) -> C3 { return C3(q.x(), -q.y(), q.z()); }, 1e-12, 1e-99, 2e2);
}
TEST_F(FFSymmetryTest, SphericalSegment)
{
    SphericalSegment ff(.79, 0, 1.24);
    run_test(&ff, [](const C3& q) -> C3 { return q.rotatedZ(pi / 3.13698); }, 8e-13, 1e-99, 2e2);
}

TEST_F(FFSymmetryTest, Spheroid)
{
    Spheroid ff(.73, .18);
    run_test(&ff, [](const C3& q) -> C3 { return q.rotatedZ(.123); }, 1e-12, 1e-99, 2e2);
}

// ****** TODO: tests that do not pass for the full q range *********
