#include "stdafx.h"

#include "mockDocuments.h"
#include "xtr\mfcHelper.h"

class UTDocuments : public ::testing::Test {
protected:
  void SetUp() override {}

  void TearDown() override {}
};

TEST_F(UTDocuments, RSFormSaveLoad) {
  const auto filePath = ::LocalPathToGlobal(LR"(Data\ТестКириллица.trs)");

  MockRSFormDoc rsdoc{};
  auto& schema = *rsdoc.schema;
  schema.title = "SaveLoad and some other text";
  schema.alias = "short";
  schema.comment = "comment";
  const auto x1 = schema.Emplace(ccl::semantic::CstType::base);
  schema.SetExpressionFor(x1, "test");
  schema.Mods().Track(x1);
  ASSERT_TRUE(rsdoc.SaveTo(filePath));

  MockRSFormDoc loadedDoc{};
  ASSERT_TRUE(loadedDoc.LoadFrom(filePath));
  std::filesystem::remove(xtr::mfc::ToUTF8(filePath));

  const auto& loadedSchema = *loadedDoc.schema;
  EXPECT_EQ(schema.title, loadedSchema.title);
  EXPECT_EQ(schema.alias, loadedSchema.alias);
  EXPECT_EQ(schema.comment, loadedSchema.comment);

  EXPECT_TRUE(loadedSchema.Contains(x1));
  EXPECT_EQ(schema.GetRS(x1).alias, loadedSchema.GetRS(x1).alias);
  EXPECT_EQ(schema.GetRS(x1).definition, loadedSchema.GetRS(x1).definition);
  EXPECT_EQ(schema.Mods().IsTracking(x1), loadedSchema.Mods().IsTracking(x1));
  EXPECT_EQ(schema.GetParse(x1).status, loadedSchema.GetParse(x1).status);
}

TEST_F(UTDocuments, RSFormLoad) {
  using xtr::TRSVersion;
  static const std::unordered_map<std::string, TRSVersion> fileNames{
    { "ext3_1997.trs", TRSVersion::old },
    { "ext3-2000.trs", TRSVersion::old },
    { "ext4-2012.trs", TRSVersion::old },
    { "ext4-2012_empty.trs", TRSVersion::old },
    { "r1092.trs", TRSVersion::r1092 },
    { "r1438.trs", TRSVersion::r1438 },
    { "r1800.trs", TRSVersion::r1800 },
    { "r47101200.trs", TRSVersion::r47101200 },
    { "r202205.trs", TRSVersion::r202205 }
  };

  MockRSFormDoc document{};
  for (const auto& [name, version] : fileNames) {
    const CString filePath = ::LocalPathToGlobal(LR"(Data\FileVers\trs\)" + xtr::mfc::ToMFC(name));
    ASSERT_TRUE(document.LoadFrom(filePath)) << "Reading from " << name;
    EXPECT_EQ(version, document.version) << "Version check for " << name;
  }
}

TEST_F(UTDocuments, RSModelLoad) {
  using xtr::RSMVersion;
  static const std::unordered_map<std::string, RSMVersion> fileNames{
    { "r1438.rsm", RSMVersion::r1438 },
    { "r1800.rsm", RSMVersion::r1800 },
    { "r47101200.rsm", RSMVersion::r47101200 },
    { "r202205.rsm", RSMVersion::r202205 }
  };

  MockRSModelDoc document{};
  for (const auto& [name, version] : fileNames) {
    const CString filePath = ::LocalPathToGlobal(LR"(Data\FileVers\rsm\)" + xtr::mfc::ToMFC(name));
    ASSERT_TRUE(document.LoadFrom(filePath)) << "Reading from " << name;
    EXPECT_EQ(version, document.version) << "Version check for " << name;
  }
}

TEST_F(UTDocuments, OSSLoad) {
  using xtr::OSSVersion;
  static const std::unordered_map<std::string, OSSVersion> fileNames{
    { "r1553\\Machine.oss", OSSVersion::r1553 },
    { "r1800\\Machine.oss", OSSVersion::r1800 },
    { "r47101200\\Machine.oss", OSSVersion::r47101200 },
    { "r202205\\Machine.oss", OSSVersion::r202205 }
  };

  MockOSSDoc document{};
  for (const auto& [name, version] : fileNames) {
    const CString filePath = ::LocalPathToGlobal(LR"(Data\FileVers\oss\)" + xtr::mfc::ToMFC(name));
    ASSERT_TRUE(document.LoadFrom(filePath)) << "Reading from " << name;
    EXPECT_EQ(version, document.version) << "Version check for " << name;
  }
}

TEST_F(UTDocuments, RSModelSaveLoad) {
  using ccl::semantic::CstType;
  using ccl::semantic::EvalStatus;
  const auto filePath = ::LocalPathToGlobal(LR"(Data\ТестКириллица.rsm)");

  MockRSModelDoc rsdoc{};
  auto& model = *rsdoc.model;
  
  model.title = "SaveLoad and some other text";
  model.alias = "short";
  model.comment = "comment";
  
  const auto x1 = model.Emplace(CstType::base);
  const auto x2 = model.Emplace(CstType::base);
  const auto s1 = model.Emplace(CstType::structured, "\xE2\x84\xAC(X1)");
  const auto d1 = model.Emplace(CstType::term, R"(X1\X1)");
  const auto a1 = model.Emplace(CstType::axiom, "1=1");
  const auto a2 = model.Emplace(CstType::axiom, "1=2");

  model.Values().AddBasicElement(x1, "1");
  model.Values().SetStructureData(s1, model.Values().SDataFor(x1).value());
  model.Calculations().RecalculateAll();
  const auto a3 = model.Emplace(CstType::axiom);

  ASSERT_TRUE(rsdoc.SaveTo(filePath));

  MockRSModelDoc loadedDoc{};
  ASSERT_TRUE(loadedDoc.LoadFrom(filePath));
  std::filesystem::remove(xtr::mfc::ToUTF8(filePath));

  const auto& loadedModel = *loadedDoc.model;
  EXPECT_EQ(model.title, loadedModel.title);
  EXPECT_EQ(model.alias, loadedModel.alias);
  EXPECT_EQ(model.comment, loadedModel.comment);

  EXPECT_TRUE(loadedModel.Contains(x1));
  EXPECT_EQ(model.GetRS(x1).alias, loadedModel.GetRS(x1).alias);
  EXPECT_EQ(model.GetRS(x1).definition, loadedModel.GetRS(x1).definition);

  EXPECT_EQ(loadedModel.Calculations()(x1), EvalStatus::HAS_DATA);
  EXPECT_EQ(loadedModel.Calculations()(x2), EvalStatus::EMPTY);
  EXPECT_EQ(loadedModel.Calculations()(s1), EvalStatus::HAS_DATA);
  EXPECT_EQ(loadedModel.Calculations()(d1), EvalStatus::EMPTY);
  EXPECT_EQ(loadedModel.Calculations()(a1), EvalStatus::HAS_DATA);
  EXPECT_EQ(loadedModel.Calculations()(a2), EvalStatus::AXIOM_FAIL);
  EXPECT_EQ(loadedModel.Calculations()(a3), EvalStatus::NEVER_CALCULATED);

  EXPECT_EQ(std::ssize(model.Core()), std::ssize(loadedModel.Core()));
  EXPECT_TRUE(loadedModel.Values().SDataFor(x2)->B().IsEmpty());
  EXPECT_FALSE(loadedModel.Values().SDataFor(x1)->B().IsEmpty());
  EXPECT_TRUE(loadedModel.Values().StatementFor(a1).value());
  EXPECT_FALSE(loadedModel.Values().StatementFor(a2).value());
  EXPECT_FALSE(loadedModel.Values().StatementFor(a3).has_value());
}

TEST_F(UTDocuments, RSModelCalculate) {
  MockRSModelDoc document{};
  const auto filePath = ::LocalPathToGlobal(LR"(Data\Model\TestCalculate.rsm)");
  ASSERT_TRUE(document.LoadFrom(filePath));
  document.model->Calculations().RecalculateAll();
  EXPECT_EQ(document.model->Calculations().Count(ccl::semantic::EvalStatus::AXIOM_FAIL), 0U);
  EXPECT_EQ(document.model->Calculations().Count(ccl::semantic::EvalStatus::INCALCULABLE), 0U);
  EXPECT_EQ(document.model->Calculations().Count(ccl::semantic::EvalStatus::NEVER_CALCULATED), 0U);
}

TEST_F(UTDocuments, OSSSaveLoad) {
  const auto filePath = ::LocalPathToGlobal(LR"(Data\ТестКириллица.oss)");
  MockOSSDoc ossdoc{};
  auto& initial = *ossdoc.oss;

  initial.title = "SaveLoad and some other text";
  initial.comment = "comment";
  const auto pid1 = initial.InsertBase()->uid;
  initial.SetPictAlias(pid1, "Alias1");

  ASSERT_TRUE(ossdoc.SaveTo(filePath));

  MockOSSDoc loadedDoc{};
  ASSERT_TRUE(loadedDoc.LoadFrom(filePath));
  std::filesystem::remove(xtr::mfc::ToUTF8(filePath));

  const auto& loaded = *loadedDoc.oss;
  EXPECT_EQ(loaded.title, initial.title);
  EXPECT_EQ(loaded.comment, initial.comment);
  EXPECT_EQ(loaded.size(), initial.size());
  ASSERT_TRUE(loaded.Contains(pid1));
  EXPECT_EQ(loaded(pid1)->alias, initial(pid1)->alias);
}