#include "FileManager.h"
#include "ChronoReadingManager.h"

const char* _gunProfileFolder="/gunprofile/";
const char* _projectileProfileFolder="/projectileprofile/";
const int maxProfileCount=128;
FileManager::FileManager() {
}
FileManager& FileManager::getInstance(){
  static FileManager instance;
  return instance;
}
void FileManager::init(){
  if (!LittleFS.begin(true)) { // true to format if not formatted
    Serial.println("LittleFS Mount Failed");
    return;
  }
}
void FileManager::saveGunProfile(GunProfile& profile){
  String filename=_gunProfileFolder;
  filename += String(millis());
  Serial.print("filename: ");
  Serial.println(filename);
  File file = LittleFS.open(filename, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open gun profile file for writing");
    return;
  }

  // Write the object's data directly as bytes
  file.write((uint8_t*)&profile, sizeof(GunProfile)); 
  file.close();
  Serial.println("GunProfile Object written to file successfully.");
}
void FileManager::removeGunProfile(GunProfile& profile){
  File directory = LittleFS.open(_gunProfileFolder, FILE_READ);
  if (!directory){
    Serial.println("failed to open gun profile folder....");
    if (!directory.isDirectory()) {
      return;
    }
  }
  if (!directory.isDirectory()) {
    Serial.println(" - not a directory, error");
    return;
  }
  directory.rewindDirectory();
  
  ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance();
  Serial.println("parsing gun profile directory....");
  File file = directory.openNextFile();
  String fs="";
  bool found=false;
  GunProfile gunProfile;
  while (file) {
    fs=_gunProfileFolder;
    fs += file.name();

    file.read((byte *)&gunProfile, sizeof(gunProfile));
    file.close(); 

    if (gunProfile.getName()==profile.getName() &&
        gunProfile.getPowerLevel()==profile.getPowerLevel()){
          Serial.print("removing: ");
          Serial.println(fs);
          LittleFS.remove(fs);
          break;
        }


    file = directory.openNextFile();
    if (file.size()==0){break;}
  }
  directory.close();
  Serial.println("done removing gun profile!");
}
void FileManager::removeAllGunProfiles(){
  File directory = LittleFS.open(_gunProfileFolder, FILE_READ);
  if (!directory){
    Serial.println("failed to open gun profile folder....");
    if (!directory.isDirectory()) {
      return;
    }
  }
  if (!directory.isDirectory()) {
    Serial.println(" - not a directory, error");
    return;
  }
  directory.rewindDirectory();

  Serial.println("parsing gun profile directory....");
  File file = directory.openNextFile();
  const char* fs;
  while (file) {
    fs=file.path();
    file.close(); 
    file = directory.openNextFile();
    Serial.print("removing: ");
    Serial.print(fs);
    bool rm=LittleFS.remove(fs);
    Serial.print(" ---> ");
    Serial.println(rm);
  }
  directory.close();
  Serial.println("done removing all gun profiles!");
}
void FileManager::loadGunProfiles(LinkedList<GunProfile>& profiles){
  //File file = LittleFS.open(filename, FILE_READ);
  File directory = LittleFS.open(_gunProfileFolder, FILE_READ);
  if (!directory){
    Serial.println("failed to open gun profile folder....");
    if (!directory.isDirectory()) {
      Serial.println(" - not a directory, generating directory for first time");
      LittleFS.mkdir(_gunProfileFolder);
      return;
    }
  }

  if (!directory.isDirectory()) {
    Serial.println(" - not a directory, error");
    return;
  }
  directory.rewindDirectory();
  
  ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance();
  Serial.println("parsing gun profile directory....");
  File file = directory.openNextFile();
    GunProfile gunProfile;
  while (file) {
    String fs=_gunProfileFolder;
    fs += file.name();
    file.read((byte *)&gunProfile, sizeof(gunProfile));
    chronoReadings.addGunProfile(gunProfile, false);
    Serial.print("added gun profile: ");
    Serial.println(file.name());

    Serial.print("Free Heap Memory: ");
    Serial.print(ESP.getFreeHeap());
    Serial.println(" bytes");
   
    file.close(); 
    file = directory.openNextFile();
    if (file.size()==0){break;}
  }

  directory.close();
  Serial.println("done loading gun profiles!");
}
void FileManager::saveProjectileProfile(ProjectileProfile& profile){
  String filename=_projectileProfileFolder;
  filename += String(millis());
  File file = LittleFS.open(filename, FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open projectile profile file for writing");
    return;
  }

  // Write the object's data directly as bytes
  file.write((uint8_t*)&profile, sizeof(ProjectileProfile)); 
  file.close();
  Serial.println("ProjectileProfile Object written to file successfully.");
}
void FileManager::removeProjectileProfile(ProjectileProfile& profile){
  File directory = LittleFS.open(_projectileProfileFolder, FILE_READ);
  if (!directory){
    Serial.println("failed to open projectile profile folder....");
    if (!directory.isDirectory()) {
      return;
    }
  }
  if (!directory.isDirectory()) {
    Serial.println(" - not a directory, error");
    return;
  }
  directory.rewindDirectory();
  
  ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance();
  Serial.println("parsing projectile profile directory....");
  File file = directory.openNextFile();
  String fs="";
  bool found=false;
  while (file) {
    fs=_projectileProfileFolder;
    fs += file.name();

    ProjectileProfile projectileProfile;
    file.read((byte *)&projectileProfile, sizeof(projectileProfile));
    file.close(); 

    if (projectileProfile.getName()==profile.getName() &&
        projectileProfile.getCaliber()==profile.getCaliber() &&
        projectileProfile.getWeight()==profile.getWeight() &&
        projectileProfile.getType()==profile.getType()){
          Serial.print("removing: ");
          Serial.println(fs);
          LittleFS.remove(fs);
          break;
        }


    file = directory.openNextFile();
    if (file.size()==0){break;}
  }
  directory.close();
  Serial.println("done removing projectile profile!");
}
void FileManager::loadProjectileProfiles(LinkedList<ProjectileProfile>& profiles){
  //File file = LittleFS.open(filename, FILE_READ);
  File directory = LittleFS.open(_projectileProfileFolder, FILE_READ);
  if (!directory){
    Serial.println("failed to open projectile profile folder....");
    if (!directory.isDirectory()) {
      Serial.println(" - not a directory, generating directory for first time");
      LittleFS.mkdir(_projectileProfileFolder);
      return;
    }
  }

  if (!directory.isDirectory()) {
    Serial.println(" - not a directory, error");
    return;
  }
  directory.rewindDirectory();
  
  ChronoReadingManager& chronoReadings = ChronoReadingManager::getInstance();
  Serial.println("parsing projectile profile directory....");
  File file = directory.openNextFile();
  while (file) {
    String fs=_projectileProfileFolder;
    fs += file.name();
    ProjectileProfile projectileProfile;
    file.read((byte *)&projectileProfile, sizeof(projectileProfile));
    chronoReadings.addProjectileProfile(projectileProfile, false);
    Serial.print("added projectile profile: ");
    Serial.println(file.name());
   
    file.close(); 
    file = directory.openNextFile();
    if (file.size()==0){break;}
  }

  directory.close();
  Serial.println("done loading projectile profiles!");
}
void FileManager::formatDisk(){
  LittleFS.format();
}