#include <cstdio>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

#include "json.hpp"

int main(int argc, char* argv[]) {
  // read 1st JSON file and store in fileOne
  std::ifstream file1;
  file1.open(argv[1]);
  nlohmann::json fileOne;
  // Store the contents filename into fileOne
  if (file1.is_open()) {
    file1 >> fileOne;
  }

  // read 2nd JSON file and store in fileTwo
  std::ifstream file2;
  file2.open(argv[2]);
  nlohmann::json fileTwo;
  // Store the contents filename into fileTwo
  if (file2.is_open()) {
    file2 >> fileTwo;
    //std::cout << "does second file exist?" << std::endl;
  }

  nlohmann::json outputJSON;            // output JSON file
  std::string sampleNameOne;            // Sample key name of first file
  std::string sampleNameTwo;            // Sample key name of second file
  int firstFileArrayElement = 0;        // current element value of the first file
  int secondFileArrayElement = 0;       // current element value of the second file
  int samplesWithConflicts = 0;         // number of samples that have conflicting results

  // iterate through the first file's samples
  for (auto itr = fileOne.begin(); itr != fileOne.end(); ++itr) {
    sampleNameOne = itr.key();
    //std::cout << "1st file sample name: " << sampleNameOne << std::endl;

    if (sampleNameOne != "metadata") {
      // iterate through the second file's samples
      for (auto itr_1 = fileTwo.begin(); itr_1 != fileTwo.end(); ++itr_1) {
        sampleNameTwo = itr_1.key();
        //std::cout << "2nd file sample name: " << sampleNameTwo << std::endl;

        int elementNumber = 0;                // element number in Sample 1 array currently being checked
        int conflictingResultsInSamples = 0;  // number of conflicts within a sample


        // check that the loops are at the same sample
        if (sampleNameOne == sampleNameTwo) {
          // iterate through the first file's sample array
          for (auto arrayItr = fileOne[sampleNameOne].begin(); arrayItr != fileOne[sampleNameOne].end(); ++arrayItr) {
            firstFileArrayElement = *arrayItr;
            //std::cout << "First File Element: " << firstFileArrayElement << std::endl;
            elementNumber++;

            int compareElementNumber = 0;      // element number in Sample 2 array currently being checked

            for (auto arrayItr_1 = fileTwo[sampleNameOne].begin(); arrayItr_1 != fileTwo[sampleNameTwo].end(); ++arrayItr_1) {
              secondFileArrayElement = *arrayItr_1;
              //std::cout << "Second File Element: " << secondFileArrayElement << std::endl;
              compareElementNumber++;

              if (elementNumber == compareElementNumber) {
                // if there is a conlfict
                if (firstFileArrayElement != secondFileArrayElement) {
                  // begin writing out the ouput for it
                  nlohmann::json conflict;
                  // make array of mismatched values
                  conflict.push_back(firstFileArrayElement);
                  conflict.push_back(secondFileArrayElement);
                  // convert key of array into string
                  std::stringstream convert2String;
                  convert2String << (elementNumber - 1);
                  std::string arrayElementNumber = convert2String.str();
                  // output the mismatch array
                  outputJSON[itr.key()]["Mismatches"][arrayElementNumber] = conflict;

                  // increase counter of number of mismatches between the two samples
                  conflictingResultsInSamples++;

                  // the first time there is a conflict in a sample
                  if (conflictingResultsInSamples == 1) {
                    // increment the counter for how many samples have conflicts
                    samplesWithConflicts++;
                    outputJSON[itr.key()]["sample1"] = itr.value();
                    outputJSON[itr_1.key()]["sample2"] = itr_1.value();
                  }

                  break;
                }
              } else if (elementNumber < compareElementNumber) {
                file1.close();break; // once it goes over the element number of the first array, the loop shouldn't keep going
              }
            }
          }
        }
      }
    }
  }

  outputJSON["metadata"]["samplesWithConflictingResults"] = samplesWithConflicts;

  outputJSON["sample1"]["metadata"]["arraySize"] = fileOne["metadata"]["arraySize"];
  outputJSON["sample1"]["metadata"]["file"] = argv[1];
  outputJSON["sample1"]["metadata"]["numSamples"] = fileOne["metadata"]["numSamples"];
  outputJSON["sample2"]["metadata"]["arraySize"] = fileTwo["metadata"]["arraySize"];
  outputJSON["sample2"]["metadata"]["file"] = argv[2];
  outputJSON["sample2"]["metadata"]["numSamples"] = fileTwo["metadata"]["numSamples"];

  // JSON output
  std::cout << outputJSON << std::endl;

  file1.close();
  file2.close();
  return 0;
}
