#include <string.h>
#include <bits/stdc++.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

//filename
const char * fileName = "/d.csv";
const char * reportFile = "/r.csv";

double max_value = 0.0;
double min_value = 100.0;
double data_array[150];
double overall_average = 0.0;
int counter = 0;
int overall_counter = 0;

int ten_min_counter = 0;
double ten_min_average = 0.0;

const int moist_sensor = 32; //pin value

void setup(){ //da goods
    serialSetup();

    write("\n");

    for(int i=0; i<86400; i++){
      overall_counter = i;
    
      append("\n");
      writeTime();
      double data = writeMoist();

      overall_average = overall_average + data;
      ten_min_average = ten_min_average + data;

      ten_min_counter++;
      if (ten_min_counter == 600){
        ten_min_counter = 0;
        data_array[counter] = ten_min_average / 600;
        ten_min_average = 0;
        counter++;
      }
      readSerial();

      delay(1000);
    }

    writeReport();
    Serial.println("End of Data Collection.");
    
    
}

void loop(){ //ya ya ya data blah blah blah, won't compile without it

}

void write(char * message){
  writeFile(SD, fileName, message);
}

void append(char * message){
  appendFile(SD, fileName, message);
}

void serialSetup(){
  Serial.begin(115200);
    if(!SD.begin()){
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();

    if(cardType == CARD_NONE){
        Serial.println("No SD card attached");
        return;
    }

    Serial.print("SD Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

void readFile(fs::FS &fs, const char * path){ //reads file content function
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if(!file){
        Serial.println("Failed to open file for reading");
        return;
    }

    Serial.print("Read from file: ");
    while(file.available()){
        Serial.write(file.read());
    }
    file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message){ //writes content to a file function
    File file = fs.open(path, FILE_WRITE);
    file.print(message);
    file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){ //writes stuff to file but doesn't delete earlier stuff function
    File file = fs.open(path, FILE_APPEND);
    file.print(message);
    file.close();
}

void writeTime(){
  append("\n");
  append("$TIME_IN_SECONDS, ");
  double time = millis() / 1000.0;

  std::string message = std::to_string(time);
  char str[1024];
  strcpy(str, message.c_str());
  append(str);
}

double writeMoist() {
  append("\n");
  append("$MOIST_IN_VOLTS, ");
  double voltage = (analogRead(moist_sensor) * (5.0 / 1023)); 
  

  if (voltage > max_value ) {
    max_value = voltage;
  }

  if (voltage < min_value) {
    min_value = voltage;
  }

  std::string message = std::to_string(voltage);
  char str[1024];
  strcpy(str, message.c_str());
  append(str);

  append("\n");

  //transfer into context
  if (voltage > 13.68){
    append("The soil is NOT HYDRATED and needs to be watered");
  } else if (voltage < 8.31) {
    append("The soil is OVERLY HYDRATED, don't water it");
  } else {
    append("The soil is HYDRATED, don't water it for a little while");
  }

  return voltage;

}



void writeReport(){
  writeFile(SD, reportFile, "REPORT");
  appendFile(SD, reportFile, "\n");

  appendFile(SD, reportFile, "MAX VALUE IN VOLTS: ");
  std::string message = std::to_string(max_value);
  char str[1024];
  strcpy(str, message.c_str());
  appendFile(SD, reportFile, str);

  appendFile(SD, reportFile, "\n");

  appendFile(SD, reportFile, "MIN VALUE IN VOLTS: ");
  message = std::to_string(min_value);
  strcpy(str, message.c_str());
  appendFile(SD, reportFile, str);

  appendFile(SD, reportFile, "\n");

  appendFile(SD, reportFile, "OVERALL AVERAGE VALUE IN VOLTS: ");

  double report_overall_average = overall_average / (overall_counter + 1);
  message = std::to_string(report_overall_average);
  strcpy(str, message.c_str());
  appendFile(SD, reportFile, str);

  appendFile(SD, reportFile, "\n");

  appendFile(SD, reportFile, "TEN MIN AVERAGE VALUES IN VOLTS: ");
  for (int i = 0; i < counter; i++){
    message = std::to_string(data_array[i]);
    strcpy(str, message.c_str());
    appendFile(SD, reportFile, str);
    appendFile(SD, reportFile, " ,");
  }

}

void printReport(){
  Serial.println();
  Serial.print("REPORT");

  Serial.println();

  Serial.print("MAX VALUE IN VOLTS: ");
  Serial.print(max_value);

  Serial.println();

  Serial.print("MIN VALUE IN VOLTS: ");
  Serial.print(min_value);

  Serial.println();

  Serial.print("OVERALL AVERAGE VALUE IN VOLTS: ");
  Serial.print(overall_average / (overall_counter + 1));

  Serial.println();

  Serial.print("TEN MIN AVERAGE VALUES IN VOLTS: ");
  for (int i = 0; i < counter; i++){
    Serial.print(data_array[i]);
    Serial.print(" ,");
  }
}


void readSerial() {
  while (Serial.available() > 0)
 {
   //Create a place to hold the incoming message
   static char message[1000];
   static unsigned int message_pos = 0;

   //Read the next available byte in the serial receive buffer
   char inByte = Serial.read();

   //Message coming in (check not terminating character) and guard for over message size
   if ( inByte != '\n' && (message_pos < 1000 - 1) )
   {
     //Add the incoming byte to our message
     message[message_pos] = inByte;
     message_pos++;
   }
   //Full message received...
   else
   {
     //Add null character to string
     message[message_pos] = '\0';

     //Write 69 to print report
     int value = std::atoi(message);
     
     if (value == 69){//haha nice
       printReport();
     }

     //Reset for the next message
     message_pos = 0;
   }
 }
}





