#include "Base/Axis/MakeScale.h"
#include "Base/Axis/Scale.h"
#include "Base/Const/Units.h"
#include "Device/Beam/Beam.h"
#include "Device/Coord/CoordSystem2D.h"
#include "Device/Detector/SphericalDetector.h"
#include "Tests/GTestWrapper/google_test.h"

class OffspecCoordsTest : public ::testing::Test {
public:
    OffspecCoords* createCoords()
    {
        const auto axes = m_detector.axesClippedToRegionOfInterest();

        std::vector<const Scale*> axes2({m_alpha_i_axis.clone(), axes[1]->clone()});
        return new OffspecCoords(std::move(axes2));
    }

protected:
    SphericalDetector m_detector{100, 0.0, 5.0 * Units::deg, 70, -2.0 * Units::deg, 1.5};
    Scale m_alpha_i_axis = EquiDivision("alpha_i", 51, 0.0, 7.0 * Units::deg);
    Beam m_beam{1, 1.0, 1.0 * Units::deg};
};


TEST_F(OffspecCoordsTest, OffspecCoords)
{
    std::unique_ptr<OffspecCoords> coords(createCoords());

    EXPECT_EQ(coords->rank(), 2u);

    EXPECT_DOUBLE_EQ(coords->calculateMin(0, Coords::UNDEFINED), 0.0);
    EXPECT_DOUBLE_EQ(coords->calculateMin(0, Coords::NBINS), 0.0);
    EXPECT_DOUBLE_EQ(coords->calculateMin(0, Coords::RADIANS), 0.0);
    EXPECT_DOUBLE_EQ(coords->calculateMin(0, Coords::DEGREES), 0.0);
    EXPECT_FAILED_ASSERT(coords->calculateMin(0, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(coords->calculateMin(0, Coords::MM));

    EXPECT_DOUBLE_EQ(coords->calculateMax(0, Coords::UNDEFINED), 7.0);
    EXPECT_DOUBLE_EQ(coords->calculateMax(0, Coords::NBINS), 51.0);
    EXPECT_DOUBLE_EQ(coords->calculateMax(0, Coords::RADIANS), Units::deg2rad(7.0));
    EXPECT_DOUBLE_EQ(coords->calculateMax(0, Coords::DEGREES), 7.0);
    EXPECT_FAILED_ASSERT(coords->calculateMax(0, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(coords->calculateMax(0, Coords::MM));

    EXPECT_DOUBLE_EQ(coords->calculateMin(1, Coords::UNDEFINED), -2.0);
    EXPECT_DOUBLE_EQ(coords->calculateMin(1, Coords::NBINS), 0.0);
    EXPECT_DOUBLE_EQ(coords->calculateMin(1, Coords::RADIANS), Units::deg2rad(-2.0));
    EXPECT_DOUBLE_EQ(coords->calculateMin(1, Coords::DEGREES), -2.0);
    EXPECT_FAILED_ASSERT(coords->calculateMin(1, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(coords->calculateMin(1, Coords::MM));

    EXPECT_DOUBLE_EQ(coords->calculateMax(1, Coords::UNDEFINED), Units::rad2deg(1.5));
    EXPECT_DOUBLE_EQ(coords->calculateMax(1, Coords::NBINS), 70.0);
    EXPECT_DOUBLE_EQ(coords->calculateMax(1, Coords::RADIANS), 1.5);
    EXPECT_DOUBLE_EQ(coords->calculateMax(1, Coords::DEGREES), Units::rad2deg(1.5));
    EXPECT_FAILED_ASSERT(coords->calculateMax(1, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(coords->calculateMax(1, Coords::MM));

    EXPECT_FAILED_ASSERT(coords->calculateMin(2, Coords::UNDEFINED));
    EXPECT_FAILED_ASSERT(coords->calculateMax(2, Coords::UNDEFINED));

    std::unique_ptr<Scale> axis(coords->convertedAxis(0, Coords::UNDEFINED));
    EXPECT_EQ(axis->min(), coords->calculateMin(0, Coords::UNDEFINED));
    EXPECT_EQ(axis->max(), coords->calculateMax(0, Coords::UNDEFINED));

    std::unique_ptr<Scale> axis2(coords->convertedAxis(1, Coords::RADIANS));
    EXPECT_EQ(axis2->min(), coords->calculateMin(1, Coords::RADIANS));
    EXPECT_EQ(axis2->max(), coords->calculateMax(1, Coords::RADIANS));

    EXPECT_FAILED_ASSERT(coords->convertedAxis(2, Coords::UNDEFINED));
    EXPECT_FAILED_ASSERT(coords->convertedAxis(1, Coords::QSPACE));
}

TEST_F(OffspecCoordsTest, OffspecCoordsClone)
{
    std::unique_ptr<OffspecCoords> coords(createCoords());
    std::unique_ptr<OffspecCoords> P_clone(coords->clone());

    EXPECT_EQ(P_clone->rank(), 2u);

    EXPECT_DOUBLE_EQ(P_clone->calculateMin(0, Coords::UNDEFINED), 0.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(0, Coords::NBINS), 0.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(0, Coords::RADIANS), 0.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(0, Coords::DEGREES), 0.0);
    EXPECT_FAILED_ASSERT(P_clone->calculateMin(0, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(P_clone->calculateMin(0, Coords::MM));

    EXPECT_DOUBLE_EQ(P_clone->calculateMax(0, Coords::UNDEFINED), 7.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(0, Coords::NBINS), 51.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(0, Coords::RADIANS), Units::deg2rad(7.0));
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(0, Coords::DEGREES), 7.0);
    EXPECT_FAILED_ASSERT(P_clone->calculateMax(0, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(P_clone->calculateMax(0, Coords::MM));

    EXPECT_DOUBLE_EQ(P_clone->calculateMin(1, Coords::UNDEFINED), -2.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(1, Coords::NBINS), 0.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(1, Coords::RADIANS), Units::deg2rad(-2.0));
    EXPECT_DOUBLE_EQ(P_clone->calculateMin(1, Coords::DEGREES), -2.0);
    EXPECT_FAILED_ASSERT(P_clone->calculateMin(1, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(P_clone->calculateMin(1, Coords::MM));

    EXPECT_DOUBLE_EQ(P_clone->calculateMax(1, Coords::UNDEFINED), Units::rad2deg(1.5));
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(1, Coords::NBINS), 70.0);
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(1, Coords::RADIANS), 1.5);
    EXPECT_DOUBLE_EQ(P_clone->calculateMax(1, Coords::DEGREES), Units::rad2deg(1.5));
    EXPECT_FAILED_ASSERT(P_clone->calculateMax(1, Coords::QSPACE));
    EXPECT_FAILED_ASSERT(P_clone->calculateMax(1, Coords::MM));

    EXPECT_FAILED_ASSERT(P_clone->calculateMin(2, Coords::UNDEFINED));
    EXPECT_FAILED_ASSERT(P_clone->calculateMax(2, Coords::UNDEFINED));
}
