#include"SDmanger.h"
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include <Arduino.h>
File Comenfile;

  SemaphoreHandle_t sd_mutex = xSemaphoreCreateMutex();

 void sdcard::lock() {
    xSemaphoreTake(sd_mutex, portMAX_DELAY);
  }

   void sdcard::unlock() {
    xSemaphoreGive(sd_mutex);
  }

void sdcard::formatSDCard() {
//  SD_MMC.end(); // 先卸载SD卡文件系统
  Serial.println("Formatting SD card...");
  esp_vfs_fat_mount_config_t mount_config = {
    .format_if_mount_failed = true,  // 不自动格式化
    .max_files = 5,
    .allocation_unit_size = 16 * 1024
  };
  sdmmc_card_t* card = nullptr;

  card= SD_MMC.card();
  //esp_err_t err = esp_vfs_fat_sdcard_format("/sdcard", card);
  // 调用真正的格式化函数
  esp_vfs_fat_mount_config_t fmt_config = mount_config;  // 也可以调整 fmt_config 参数
   esp_err_t err = esp_vfs_fat_sdcard_format_cfg("/sdcard", card, &fmt_config);
  Serial.println("Formatting completed");
  if (err == ESP_OK) {
    Serial.println("SD card formatted successfully");
  } else {
    Serial.printf("Format failed: %s\n", esp_err_to_name(err));
  }

   
}
#define sd_cmd 7
#define sd_clk 6
#define sd_dat0 5
#define sd_dat1 4
#define sd_dat2 16
#define sd_dat3 15
int sdcard::init_sdcard()
{
      pinMode(48, OUTPUT);
    digitalWrite(48, HIGH);
    vTaskDelay(1000);
   SD_MMC.setPins(9,10,11,12,13,14);
  //格式化sd卡
      //SD_MMC.setPins(sd_clk,sd_cmd,sd_dat0,sd_dat1,sd_dat2,sd_dat3);
  
  int succ = SD_MMC.begin("/sdcard", false,true);

  if (succ) {
    Serial.printf("SD_MMC Begin: %d\n", succ);
    uint8_t cardType = SD_MMC.cardType();
    Serial.print("SD_MMC 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_MMC.cardSize() / (1024 * 1024);
    Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);

  } else {
    Serial.printf("Failed to mount SD card VFAT filesystem. \n");
    Serial.println("Do you have an SD Card installed?");
    Serial.println("Check pin 12 and 13, not grounded, or grounded with 10k resistors!\n\n");
   // major_fail();
  }

  return ESP_OK;
}



 void sdcard::mylistDir( const char * dirname, uint8_t levels) {

  Serial.printf("Listing directory: %s\n", "/");
  String dir(dirname);
  File root = SD_MMC.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return;
  }

  File filex = root.openNextFile();
  while (filex) {
    if (filex.isDirectory()) 
    {
      Serial.print("  DIR : ");
      Serial.println(filex.name());
      if (levels) {
        String filename=dir+"/"+String(filex.name());
        mylistDir( filename.c_str(), levels - 1);
      }
    } 
    else
    {
      Serial.print("  FILE: ");
      Serial.print(filex.name());
      Serial.print("  SIZE: ");
      Serial.println(filex.size());
    }
    filex.close();
    filex = root.openNextFile();
  }
}

bool sdcard::fileexists(const char * path)
{
  File f = SD_MMC.open(path);
  if (!f) {
    f.close();
    return false;
  }
  f.close();
  return true;
}

bool sdcard::ListDir(const char * dirname,Vector <String> &stringlist)
{
  stringlist.clear();
  Serial.println("Listing directory: ");
 
  String dir(dirname);
  File root = SD_MMC.open(dirname);
  if (!root) {
    Serial.println("Failed to open directory");
     return true;
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
      return true;
  }

  File filex = root.openNextFile();
  while (filex) 
  {
    if (filex.isDirectory()) {
    
    } else {
       String filename=dir+"/"+String(filex.name());
      stringlist.push_back(filename);
     
      if (stringlist.size()==stringlist.max_size())
      {
          return false;
        /* code */
      }
      
    }
    filex.close();
    filex = root.openNextFile();
  }
filex.close();
  return true;

}


 void sdcard::delete_old_stuff() {

  Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
  Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));

  //listDir( "/", 0);

  float full = 1.0 * SD_MMC.usedBytes() / SD_MMC.totalBytes();;
  if (full  <  0.8) {
    Serial.printf("Nothing deleted, %.1f%% disk full\n", 100.0 * full);
  } else {
    Serial.printf("Disk is %.1f%% full ... deleting oldest file\n", 100.0 * full);
    while (full > 0.8) {

      double del_number = 999999999;
      char del_numbername[50];

      File f = SD_MMC.open("/");

      File file = f.openNextFile();

      while (file) {
        //Serial.println(file.name());
        if (!file.isDirectory()) {

          char foldname[50];
          strcpy(foldname, file.name());
          for ( int x = 0; x < 50; x++) {
            if ( (foldname[x] >= 0x30 && foldname[x] <= 0x39) || foldname[x] == 0x2E) {
            } else {
              if (foldname[x] != 0) foldname[x] = 0x20;
            }
          }

          double i = atof(foldname);
          if ( i > 0 && i < del_number) {
            strcpy (del_numbername, file.name());
            del_number = i;
          }
          //Serial.printf("Name is %s, number is %f\n", foldname, i);
        }
        file = f.openNextFile();

      }
      Serial.printf("lowest is Name is %s, number is %f\n", del_numbername, del_number);
      if (del_number < 999999999) {
        deleteFolderOrFile(del_numbername);
      }
      full = 1.0 * SD_MMC.usedBytes() / SD_MMC.totalBytes();
      Serial.printf("Disk is %.1f%% full ... \n", 100.0 * full);
      f.close();
    }
  }
}

 void sdcard::deleteFolderOrFile(const char * val) {
  // Function provided by user @gemi254
  Serial.printf("Deleting : %s\n", val);
  File f = SD_MMC.open(val);
  if (!f) {
    Serial.printf("Failed to open %s\n", val);
    return;
  }

  if (f.isDirectory()) {
    File file = f.openNextFile();
    while (file) {
      if (file.isDirectory()) {
        Serial.print("  DIR : ");
        Serial.println(file.name());
      } else {
        Serial.print("  FILE: ");
        Serial.print(file.name());
        Serial.print("  SIZE: ");
        Serial.print(file.size());
        if (SD_MMC.remove(file.name())) {
          Serial.println(" deleted.");
        } else {
          Serial.println(" FAILED.");
        }
      }
      file = f.openNextFile();
    }
    f.close();
    //Remove the dir
    if (SD_MMC.rmdir(val)) {
      Serial.printf("Dir %s removed\n", val);
    } else {
      Serial.println("Remove dir failed");
    }

  } else {
    //Remove the file
    if (SD_MMC.remove(val)) {
      Serial.printf("File %s deleted\n", val);
    } else {
      Serial.println("Delete failed");
    }
  }
}

 void sdcard:: testwriet()
{
    File file;
      file = SD_MMC.open("/gps/try.txt", "wb");
      file.println("hello world");
      file.flush();
      file.close();
}



  void sdcard::WriteStringToFile(String name,String Str)
  {
      File file;

      file = SD_MMC.open(name, "w+");
      file.println(Str);
      file.flush();
      file.close();
  }
    void sdcard::WriteStringToFile(String name,char *data,size_t lenth)
  {
      File file;

      file = SD_MMC.open(name, "wb");
      file.write((const byte *)data,lenth);
      file.flush();
      file.close();
  }
 bool sdcard::Mkdir(String path)
  {
     return SD_MMC.mkdir(path);
  }


  
namespace sdcard
{
  void openFileformWirte(String Path)
  {
    if (Comenfile.available())
    {
      Comenfile.close();
      /* code */
    }
    Comenfile = SD_MMC.open(Path, "w+");
  
  }
  
  void WritetoFileCommen(String Str)
  {
    if (Comenfile.available())
    {
      Comenfile.print(Str);
      Comenfile.flush();
      /* code */
    }
  }
  
  void WritetoFileCommen(char *data,size_t lenth)
  {
    if (Comenfile.available())
    {
      Comenfile.write((const byte *)data,lenth);
      Comenfile.flush();
      /* code */
    }
    
  }
  String ReadFileToString(const char * path)
  {
    String ret="";
    File file=SD_MMC.open(path,"r");
    if (!file)
    {
        return ret;
      /* code */
    }
    while (file.available())
    {
        ret+=char(file.read());
      /* code */
    }
    file.close();
    return ret;
  }
  void closeCommenFile()
  {
    if (Comenfile.available())
    {
      Comenfile.close();
      /* code */
    }
    
  }
}