#include <boost/test/unit_test.hpp>

#include "../../plot/statistics.h"
#include "../../plot/vectorimage.h"

namespace {
void TestMean(std::initializer_list<float> list, float expected) {
  std::vector<float> v{list};
  VectorImage image(std::move(v), list.size());
  float mean = -1000.0;
  float stddev;
  WinsorizedMeanAndStdDev(image, mean, stddev);
  BOOST_CHECK(std::isfinite(mean));
  if (expected == 0.0)
    BOOST_CHECK_LT(std::abs(mean), 1e-6);
  else
    BOOST_CHECK_CLOSE_FRACTION(mean, expected, 1e-6);
}

void TestStddev(std::initializer_list<float> list, float expected) {
  std::vector<float> v{list};
  VectorImage image(std::move(v), list.size());
  float mean;
  float stddev = -1000.0;
  WinsorizedMeanAndStdDev(image, mean, stddev);
  BOOST_CHECK(std::isfinite(stddev));
  if (expected == 0.0)
    BOOST_CHECK_LT(std::abs(stddev), 1e-6);
  else
    BOOST_CHECK_CLOSE_FRACTION(stddev, expected, 1e-6);
}
}  // namespace

BOOST_AUTO_TEST_SUITE(plot_statistics, *boost::unit_test::label("statistics"))

BOOST_AUTO_TEST_CASE(winsorized_mean) {
  TestMean({0.0}, 0.0);
  TestMean({1.0}, 1.0);
  TestMean({-3.14e7}, -3.14e7);
  TestMean({-1.0, 0.0, 1.0}, 0.0);
  TestMean({-1000.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1e7},
           4.5);
  TestMean({-1000.0, -12.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1e7},
           2.5);
  TestMean({-1000.0, -12.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 21.0, 1e7},
           4.5);
  TestMean({-12.0, 4.0, 2.0, 21.0, 3.0, 8.0, 1e7, 5.0, -1000.0, 1.0, 7.0, 6.0},
           4.5);
  TestMean({12.0, 10.0, std::numeric_limits<float>::quiet_NaN(), 8.0}, 10.0);
}

BOOST_AUTO_TEST_CASE(winsorized_stddev) {
  constexpr float factor = 1.54;
  TestStddev({0.0}, 0.0);
  TestStddev({1.0}, 0.0);
  TestStddev({-3.14e7}, 0.0);
  TestStddev({-1.0, 0.0, 1.0}, std::sqrt(factor * 2.0 / 3.0));
  TestStddev({-1000.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1e7},
             3.97303414);
  TestStddev({-1000.0, -12.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 1e7},
             8.62003517);
  TestStddev(
      {-1000.0, -12.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 21.0, 1e7},
      12.0476141);
  TestStddev(
      {-12.0, 4.0, 2.0, 21.0, 3.0, 8.0, 1e7, 5.0, -1000.0, 1.0, 7.0, 6.0},
      12.0476141);
  TestStddev({12.0, 10.0, std::numeric_limits<float>::quiet_NaN(), 8.0},
             std::sqrt(factor * 8.0 / 3.0));
}

BOOST_AUTO_TEST_SUITE_END()
