#include "YODA/Estimate0D.h"
#include "YODA/Utils/MetaUtils.h"
#include "YODA/Utils/MathUtils.h"
#include <cmath>
#include <fstream>

using namespace YODA;

//TestHelpers::TestData testData;

auto testEstimate() {
  Estimate0D e1;
  if (e1.dim() != 1)  return CHECK_TEST_RES(false);

  // Set central value / error
  e1.setVal(42);
  e1.setErr({-4,5});
  e1.setErr({2,-3}, "syst");
  e1.setErr({-1,2}, "stats");
  if (e1.val() != 42)  return CHECK_TEST_RES(false);

  std::pair<double,double> errDU = e1.errDownUp();
  if (errDU.first != -4 || errDU.second != 5)  return CHECK_TEST_RES(false);

  std::pair<double,double> errNP = e1.errNegPos("syst");
  if (errNP.first != -3 || errNP.second != 2)  return CHECK_TEST_RES(false);
  if (e1.errNeg("stats") != -1 || e1.errPos("stats") != 2)  return CHECK_TEST_RES(false);

  Estimate0D e2(2, {6,-8});
  if (e2.relErrDown() != 3 || e2.relErrUp() != -4)  return CHECK_TEST_RES(false);
  if (e2.valMax() != 8 || e2.valMin() != -6)        return CHECK_TEST_RES(false);

  Estimate0D e3(2, {-6,8}, "syst1");
  e3.setErr({-8,6}, "syst2");
  if (e3.totalErr().first != -10 || e3.totalErr().second != 10)  return CHECK_TEST_RES(false);
  if (e3.quadSum().first != -10 || e3.quadSum().second != 10)  return CHECK_TEST_RES(false);

  Estimate0D e4 = e3 + Estimate0D(2, {-8,6}, "syst1");
  if (e4.val() != 4)  return CHECK_TEST_RES(false);
  std::pair<double,double> errDU2 = e4.errDownUp("syst1");
  if (errDU2.first != -14 || errDU2.second != 14)  return CHECK_TEST_RES(false);
  std::pair<double,double> errDU3 = e4.errDownUp("syst2");
  if (errDU3.first != -8 || errDU3.second != 6)  return CHECK_TEST_RES(false);

  e3.setErr({-3,3}, "cor,syst3");
  Estimate0D e5 = e3 + Estimate0D(3, {-4,4}, "cor,syst3");
  if (e5.val() != 5)  return CHECK_TEST_RES(false);
  std::pair<double,double> errDU4 = e5.errDownUp("cor,syst3");
  if (errDU4.first != -7 || errDU4.second != 7)  return CHECK_TEST_RES(false);

  Estimate0D e6 = e3 - Estimate0D(3, {-4,4}, "cor,syst3");
  if (e6.val() != -1)  return CHECK_TEST_RES(false);
  std::pair<double,double> errDU5 = e6.errDownUp("cor,syst3");
  if (errDU5.first != -7 || errDU5.second != 7)  return CHECK_TEST_RES(false);

  e6.scale(10);
  if (e6.val() != -10)  return CHECK_TEST_RES(false);
  std::pair<double,double> errDU6 = e6.errDownUp("cor,syst3");
  if (errDU6.first != -70 || errDU6.second != 70)  return CHECK_TEST_RES(false);

  Estimate0D* eptr = e6.newclone();
  if (eptr->val() != -10)  return CHECK_TEST_RES(false);

  std::map<std::string,std::pair<double,double>> errMap = { {"syst", {-0.1,0.1}} };
  *eptr = Estimate0D(1.0, errMap);
  if (eptr->val() != 1.)  return CHECK_TEST_RES(false);

  eptr->reset();
  if ( ! std::isnan(eptr->val()) )  return CHECK_TEST_RES(false);

  Estimate0D e7( Estimate(2, {-8,6}, "syst1") );
  if (e7.val() != 2)  return CHECK_TEST_RES(false);

  const Estimate est(4, {-8,6}, "syst1");
  Estimate0D e8(est);
  if (e8.val() != 4)  return CHECK_TEST_RES(false);

  const std::vector<double> e7vec = e7.serializeContent();
  const std::vector<double> aovec = e7.mkInert()->serializeContent();
  if (!std::equal(e7vec.begin(), e7vec.end(), aovec.begin()))  return CHECK_TEST_RES(false);

  return CHECK_TEST_RES(true);
}


int main() {

  int rtn = CHECK_TEST_RES( testEstimate() == EXIT_SUCCESS );

  return rtn;
}
