#include <gtest/gtest.h>

#include <algorithm>
#include <fstream>
#include <string>

#include "io/gff3/GFF3Writer.h"
#include "Individual.h"
#include "TranscriptionTerminationSequence.h"

#include "gtest_utils.h"

using namespace aevol;

#ifdef BASE_4
// Define arbitrary sequences
std::array<std::string, 5> as = {
    "1201231032",
    "3310132320",
    "33012002133303",
    "0023000123311",
    "20112322013212012332103210"
};

// Define arbitrary genes
std::string start = "013";
std::array<std::string, 3> stop = {
  std::string("103"),
  std::string("130"),
  std::string("100")
};
std::array<std::string, 2> gene = {
    std::string(SHINE_DAL_SEQ) + "1121" + start + "231033013" + stop[1],
    std::string(SHINE_DAL_SEQ) + "0100" + start + "230233133023322" + stop[0]
};
std::array<std::string, 2> gene_nostop = {
    std::string(SHINE_DAL_SEQ) + "1111" + start + "231133231033013",
    std::string(SHINE_DAL_SEQ) + "0110" + start + "233322023313302"
};

// Define an arbitrary terminator
std::string term = "23320003223";

// Define a few arbitrary promoters
std::array<std::string, 2> prom = {
    "3322022010110333112023", // dist from consensus: 2
    "3022022010312333112012"  // dist from consensus: 3
};

TEST(GFF3_Test_4B, WriteGFF) {
  // Setup dummy environment
  ParamValues default_param_values;
  exp_setup->load_from_params(default_param_values);
  exp_setup->set_farthest(false);
  auto target = PhenotypicTarget::make_from_constituents(default_param_values.phenotypic_target_constituent,
                                                         default_param_values.fuzzy_flavor,
                                                         default_param_values.env_sampling);

  // Build genome
  auto to_be_inverted_1 = std::make_pair(0, prom[1] + as[1] + gene_nostop[0]);
  auto genome = to_be_inverted_1.second + as[4] + stop[1] + prom[0] + as[0] + prom[1] + as[1] + gene[0] + as[2] + term + as[3];
  auto to_be_inverted_2 = std::make_pair(genome.size(), std::string("000000000000") + prom[0] + as[1] + gene[1] + std::string("000000000000"));
  genome += to_be_inverted_2.second;
  genome += prom[0] + as[3] + gene_nostop[1];
  auto indiv = Individual::make_from_sequence(genome);
  indiv->mutable_dna().do_inversion(to_be_inverted_1.first, to_be_inverted_1.first + to_be_inverted_1.second.size());
  indiv->mutable_dna().do_inversion(to_be_inverted_2.first, to_be_inverted_2.first + to_be_inverted_2.second.size());

  indiv->evaluate(.1, 0, *target);
  gff3::write_individual_gff3("Seq01", *indiv, "./4b.gff");

  expect_file_eq("test_data/gff/4b_ref.gff", "4b.gff");
}
#elif BASE_2
// Define arbitrary sequences
std::array<std::string, 5> as = {
    "1001001110010110",
    "110111100110",
    "0111111110010111011100",
    "100010001100010001111",
    "11001011001100100001010000000110111"
};

// Define arbitrary genes
std::string start = "000";
std::string stop = "001";
std::array<std::string, 2> gene = {
    std::string(SHINE_DAL_SEQ) + "1100" + start + "010010011111101111011100000111011" + stop,
    std::string(SHINE_DAL_SEQ) + "0100" + start + "000101100110010000101000000" + stop
};
std::array<std::string, 2> gene_nostop = {
    std::string(SHINE_DAL_SEQ) + "0111" + start + "100111111011110011000101111111100",
    std::string(SHINE_DAL_SEQ) + "0110" + start + "000100011110011001"
};

// Define an arbitrary terminator
std::string term = "01110100001";

// Define a few arbitrary promoters
std::array<std::string, 2> prom = {
    "0101011000110011010110", // dist from consensus: 2
    "0100010001110010011110"  // dist from consensus: 3
};

#if defined LINEAR_CHRSM && defined DIPLOID && defined SEX
TEST(GFF3_Test_EUK, WriteGFF) {
  // Setup dummy environment
  ParamValues default_param_values;
  exp_setup->load_from_params(default_param_values);
  exp_setup->set_farthest(false);
  auto target = PhenotypicTarget::make_from_constituents(default_param_values.phenotypic_target_constituent,
                                                         default_param_values.fuzzy_flavor,
                                                         default_param_values.env_sampling);

  // Build genome
  auto chromA = prom[1] + as[0] + gene[1] + as[4] + gene[0] + term + prom[0] + gene_nostop[0] + prom[1];
  auto chromB = term + as[1] + gene[0] + term + prom[0] + gene[1] + term + as[3];
  auto indiv = Individual::make_from_sequences(chromA, chromB);
  indiv->mutable_dna(Chrsm::B).do_inversion(0, chromB.size() - as[3].size());
  // std::cout << indiv->dna(Chrsm::A).subseq(255, 11, Strand::LEADING) << std::endl;

  indiv->evaluate(.1, 0, *target);
  gff3::write_individual_gff3("Seq01", *indiv, "./euk.gff");

  expect_file_eq("test_data/gff/euk_ref.gff", "euk.gff");
}
#endif

#endif
