/////////////////////// Qt includes
#include <QDebug>
#include <QString>
#include <QDir>


/////////////////////// Catch2 includes
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>


/////////////////////// Local includes
#include "TestUtils.hpp"
#include "MsXpS/libXpertMassCore/MassCollection.hpp"

namespace MsXpS
{
namespace libXpertMassCore
{

SCENARIO("MassCollection objects can be constructed with a name and masses",
         "[MassCollection]")
{
  GIVEN(
    "A masses-as-text string and a vector of double values representing "
    "exactly the same data")
  {
    QString masses_as_text("123.321\n1234.4321\n12345.54321\n123456.654321");
    std::vector<double> masses{123.321, 1234.4321, 12345.54321, 123456.654321};

    WHEN("MassCollection instances are created with these")
    {
      // Trick to test setName()
      MassCollection mass_collection_1("other_mono_masses", masses_as_text);
      mass_collection_1.setName("mono_masses");
      mass_collection_1.setComment("This is a comment");

      MassCollection mass_collection_2("mono_masses", masses);
      mass_collection_2.setComment("This is a comment");

      THEN("Both MassCollection instances should be identical")
      {
        REQUIRE(mass_collection_1.isValid());
        REQUIRE(mass_collection_2.isValid());

        REQUIRE(mass_collection_1.getName().toStdString() == "mono_masses");
        REQUIRE(mass_collection_1.getComment().toStdString() ==
                "This is a comment");

        REQUIRE(mass_collection_2.getName().toStdString() == "mono_masses");
        REQUIRE(mass_collection_2.getComment().toStdString() ==
                "This is a comment");

        REQUIRE(mass_collection_1.size() == mass_collection_2.size());

        for(std::size_t iter = 0; iter < mass_collection_1.size(); ++iter)
          REQUIRE(mass_collection_1.getMassesCstRef().at(iter) ==
                  mass_collection_2.getMassesCstRef().at(iter));
      }

      WHEN("Copy-constructing or assigning new MassCollection objects")
      {
        MassCollection another_other_mass_collection(mass_collection_1);
        MassCollection other_mass_collection("different_name");
        other_mass_collection = another_other_mass_collection;

        THEN("All the MassCollection instances should be identical")
        {
          REQUIRE(other_mass_collection.isValid());

          REQUIRE(mass_collection_1.getName().toStdString() == "mono_masses");
          REQUIRE(mass_collection_1.getComment().toStdString() ==
                  "This is a comment");

          REQUIRE(other_mass_collection.size() == mass_collection_1.size());

          for(std::size_t iter = 0; iter < mass_collection_1.size(); ++iter)
            {
              // Trick to use both versio of getMassesRef:
              REQUIRE(other_mass_collection.getMassesCstRef().at(iter) ==
                      mass_collection_1.getMassesRef().at(iter));
              // Use also the other function getMassAtIndex()
              REQUIRE(other_mass_collection.getMassAtIndex(iter) ==
                      mass_collection_1.getMassAtIndex(iter));
            }
        }
      }

      WHEN("Requesting the masses in the form of a text string")
      {
        QString masses_as_text = mass_collection_1.massesToText();

        THEN("The text should be as expected")
        {
          REQUIRE(masses_as_text.toStdString() ==
                  "123.321000\n1234.432100\n12345.543210\n123456.654321\n");
        }
      }

      WHEN("When adding one mass to the masses")
      {
        mass_collection_1.addMass(1.0000000000);
        QString masses_as_text = mass_collection_1.massesToText();

        THEN("The new text should be as expected")
        {
          REQUIRE(masses_as_text.toStdString() ==
                  "124.321000\n1235.432100\n12346.543210\n123457.654321\n");
        }
      }

      WHEN("When asking for MassCollection validation")
      {
        ErrorList error_list;
        bool is_valid = mass_collection_1.validate(&error_list);

        THEN("The MassCollection instance should validate succesfully")
        {
          REQUIRE(is_valid);
        }
      }

      WHEN("Sorting masses descending")
      {
        mass_collection_1.sortDescending();

        THEN("The values should sort correctly")
        {
          REQUIRE_THAT(mass_collection_1.getMassesCstRef().front(),
                       Catch::Matchers::WithinAbs(123456.654321, 0.0000000001));

          REQUIRE_THAT(mass_collection_1.getMassesCstRef().back(),
                       Catch::Matchers::WithinAbs(123.321, 0.0000000001));
        }

        AND_WHEN("Sorted back in ascending order")
        {
          mass_collection_1.sortAscending();
          THEN("The values should sort correctly")
          {
            REQUIRE_THAT(mass_collection_1.getMassesCstRef().front(),
                         Catch::Matchers::WithinAbs(123.321, 0.0000000001));

            REQUIRE_THAT(
              mass_collection_1.getMassesCstRef().back(),
              Catch::Matchers::WithinAbs(123456.654321, 0.0000000001));
          }

          AND_WHEN("removeLessThan() is called")
          {
            mass_collection_1.removeLessThan(500);
            THEN("The remainig values should be correct")
            {
              REQUIRE_THAT(mass_collection_1.getMassesCstRef().front(),
                           Catch::Matchers::WithinAbs(1234.4321, 0.0000000001));

              REQUIRE_THAT(
                mass_collection_1.getMassesCstRef().back(),
                Catch::Matchers::WithinAbs(123456.654321, 0.0000000001));
            }
          }
        }
      }
    }
  }
}

} // namespace libXpertMassCore
} // namespace MsXpS
