#include <Arduino.h>

#include "Settings.h"
#include "SPIFFSEditor.h"
#include <esp_partition.h>

inline String format_float(float v, int d);
String get_program(uint8_t s);
String get_beer_program();
String get_dist_program();
String get_nbk_program();
void SendMsg(const String& m, MESSAGE_TYPE msg_type);

String PrgFName() {
  String FName;
  if (Samovar_CR_Mode == SAMOVAR_BEER_MODE) {
    FName = "/p_beer.txt";
  } else if (Samovar_CR_Mode == SAMOVAR_CHEESE_MODE) {
    FName = "/p_cheese.txt";
  }  else if (Samovar_CR_Mode == SAMOVAR_DISTILLATION_MODE) {
    FName = "/p_dist.txt";
  }else if (Samovar_CR_Mode == SAMOVAR_BK_MODE) {
    FName = "/p_bk.txt";
  } else if (Samovar_CR_Mode == SAMOVAR_NBK_MODE) {
    FName = "/p_nbk.txt";
  } else {
    FName = "/p_rect.txt";
  }
  return FName;
}
void ReadPrgFromFS() {
  String Prg;
  File filePrg = SPIFFS.open(PrgFName());
  if (filePrg) {
    Prg = filePrg.readString();
    Prg.trim();
    filePrg.close();
    if (Samovar_Mode == SAMOVAR_BEER_MODE) {
      set_beer_program(Prg);
    } else if (Samovar_Mode == SAMOVAR_CHEESE_MODE) {
      set_cheese_program(Prg);
    } else if (Samovar_Mode == SAMOVAR_DISTILLATION_MODE) {
      set_dist_program(Prg);
    } else if (Samovar_Mode == SAMOVAR_NBK_MODE) {
      set_nbk_program(Prg);
    } else {
      set_program(Prg);
    }
  }
}
void SavePrgToFS() {
  String Prg;
    if (Samovar_Mode == SAMOVAR_BEER_MODE) {
      Prg = get_beer_program();
    } else if (Samovar_Mode == SAMOVAR_CHEESE_MODE) {
      Prg = get_cheese_program();
    } else if (Samovar_Mode == SAMOVAR_DISTILLATION_MODE) {
      Prg = get_dist_program();
    } else if (Samovar_Mode == SAMOVAR_NBK_MODE) {
      Prg = get_nbk_program();
    } else {
      Prg = get_program(MAX_PRG);
    }
  File filePrg = SPIFFS.open(PrgFName(), FILE_WRITE);
  filePrg.print(Prg);
  filePrg.close();
}
bool mountSPIFFS() {
  // Сначала ищем раздел с точным именем "spiffs"
  const esp_partition_t* partition = esp_partition_find_first(
    ESP_PARTITION_TYPE_DATA, 
    ESP_PARTITION_SUBTYPE_DATA_SPIFFS, 
    "spiffs"
  );
  // Если не нашли с именем "spiffs", ищем любой раздел типа data/spiffs
  if (partition == NULL) {
    SerialMsg("Partition 'spiffs' not found, searching for any SPIFFS partition...",1);
    partition = esp_partition_find_first(
      ESP_PARTITION_TYPE_DATA, 
      ESP_PARTITION_SUBTYPE_DATA_SPIFFS, 
      NULL
    );
  }
  // Если раздел не найден вообще
  if (partition == NULL) {
    SerialMsg("ERROR: No SPIFFS partition found!",1);
    SerialMsg("Check your partition table configuration",1);
    return false;
  }
  // Выводим информацию о найденном разделе
  SerialMsg("Found SPIFFS partition: "+ String(partition->label), 1);
  Serial.printf("Address: 0x%08X, Size: %d bytes\n", partition->address, partition->size);
  
  // Пытаемся смонтировать
  if (!SPIFFS.begin(false)) {
    SerialMsg("ERROR: SPIFFS mount failed!",1);
    SerialMsg("Try formatting the partition or check for errors",1);
    return false;
  }
  // Успешное монтирование
  Serial.printf("SPIFFS mounted successfully! Total: %d bytes, Used: %d bytes\n", 
                SPIFFS.totalBytes(), SPIFFS.usedBytes());
  return true;
}
String formatBytes(size_t bytes) {//format bytes
  if (bytes < 1024) {
    return String(bytes) + "B";
  } else if (bytes < (1024 * 1024)) {
    return String(bytes / 1024.0) + "KB";
  } else if (bytes < (1024 * 1024 * 1024)) {
    return String(bytes / 1024.0 / 1024.0) + "MB";
  } else {
    return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
  }
}
void FS_init(void) {// Инициализация FS
  if (!mountSPIFFS()) BrokenFS = true;
  total_byte = SPIFFS.totalBytes();
}
bool exists(String path) {
  static bool yes;
  File file = SPIFFS.open(path, "r");
  if (!file.isDirectory()) {
    yes = true;
  } else {
    yes = false;
  }
  file.close();
  return yes;
}

void create_data() {

  if (fileToAppend) {
    fileToAppend.close(); // Close existing file handle if open
  }

  //Выведем в сериал текущую программу отбора
  if (Samovar_Mode == SAMOVAR_RECTIFICATION_MODE || Samovar_Mode == SAMOVAR_BEER_MODE || Samovar_Mode == SAMOVAR_CHEESE_MODE || Samovar_Mode == SAMOVAR_DISTILLATION_MODE || Samovar_Mode == SAMOVAR_NBK_MODE) {
    if (Samovar_Mode == SAMOVAR_RECTIFICATION_MODE) {
      Serial.println(get_program(MAX_PRG));
    } else if (Samovar_Mode == SAMOVAR_BEER_MODE) {
      Serial.println(get_beer_program());
    } else if (Samovar_Mode == SAMOVAR_CHEESE_MODE) {
      Serial.println(get_cheese_program());
    } else if (Samovar_Mode == SAMOVAR_DISTILLATION_MODE) {
      Serial.println(get_dist_program());
    } else if (Samovar_Mode == SAMOVAR_NBK_MODE) {
      Serial.println(get_nbk_program());
    }
  }
  if (SamSetup.UseLog) {
    //Удаляем старый файл с архивным логом
    if (SPIFFS.exists("/data_old.csv")) {
      SPIFFS.remove("/data_old.csv");
    }
    //Переименовываем файл с логом в архивный (на всякий случай)
    if (SPIFFS.exists("/data.csv")) {
      if (fileToAppend) {
        fileToAppend.close();
      }

      SPIFFS.rename("/data.csv", "/data_old.csv");
    }
    File fileToWrite = SPIFFS.open("/data.csv", FILE_WRITE);
    String str = "Date,Steam,Pipe,Water,Tank,Pressure";
      str += ",ProgNum";
    fileToWrite.println(str);

    fileToWrite.close();
  }
  SteamSensor.PrevTemp = 0;
  PipeSensor.PrevTemp = 0;
  WaterSensor.PrevTemp = 0;
  TankSensor.PrevTemp = 0;
  bme_prev_pressure = 0;

  if (SamSetup.UseLog) {
    fileToAppend = SPIFFS.open("/data.csv", FILE_APPEND);
    append_data();
  }
}

String append_data() {
  bool w = false;
  if (SamSetup.UseLog && !fileToAppend) {
    fileToAppend = SPIFFS.open("/data.csv", FILE_APPEND);
  }
  //Если режим ректификация и идет отбор, запишем в файл текущий статус
  if (SamSetup.UseStLog) {//Если включено в настройках
    STcnt++;
    if ((Samovar_Mode == SAMOVAR_RECTIFICATION_MODE || Samovar_Mode == SAMOVAR_BEER_MODE || Samovar_Mode == SAMOVAR_CHEESE_MODE 
        || Samovar_Mode == SAMOVAR_DISTILLATION_MODE || Samovar_Mode == SAMOVAR_NBK_MODE) && STcnt > 10) {
      File fileState = SPIFFS.open("/state.csv", FILE_WRITE);
      String sapd = "P=" + String(ProgramNum + 1);
      if (Samovar_Mode == SAMOVAR_RECTIFICATION_MODE) {
        sapd += ";V=" + String(get_liquid_volume_by_step(stepper.getCurrent()));
      } else if (Samovar_Mode == SAMOVAR_BEER_MODE || Samovar_Mode == SAMOVAR_CHEESE_MODE ) {
        sapd += ";T=" + WthdrwTimeS;
      }
      fileState.println(sapd);
      //Serial.println(sapd);
      fileState.close();
      STcnt = 0;
    }
  }

  //Если значения лога совпадают с предыдущим - в файл писать не будем
  if (!SamSetup.NoLogCh) { //Если явно не запрещено в настройках
    if (SteamSensor.avgTemp != SteamSensor.LogPrevTemp) {
      SteamSensor.LogPrevTemp = SteamSensor.avgTemp;
      w = true;
    } else if (PipeSensor.avgTemp != PipeSensor.LogPrevTemp) {
      PipeSensor.LogPrevTemp = PipeSensor.avgTemp;
      w = true;
    } else if (WaterSensor.avgTemp != WaterSensor.LogPrevTemp) {
      WaterSensor.LogPrevTemp = WaterSensor.avgTemp;
      w = true;
    } else if (TankSensor.avgTemp != TankSensor.LogPrevTemp) {
      TankSensor.LogPrevTemp = TankSensor.avgTemp;
      w = true;
    } else if (bme_prev_pressure != bme_pressure) {
      bme_prev_pressure = bme_pressure;
      w = true;//Возможно стоит отключить
    } else if (prev_ProgramNum != ProgramNum) {
      prev_ProgramNum = ProgramNum;
      w = true;
    }
  }

  if (w || SamSetup.NoLogCh) {
    String str;
    str = Crt + ",";
    str += format_float(SteamSensor.avgTemp, 3);
    str += ",";
    str += format_float(PipeSensor.avgTemp, 3);
    str += ",";
    str += format_float(WaterSensor.avgTemp, 3);
    str += ",";
    str += format_float(TankSensor.avgTemp, 3);
    str += ",";
    str += format_float(bme_pressure, 2);
    str += ",";
    str += ProgramNum + 1;
    if (SamSetup.UseLog) {
      fileToAppend.println(str);
      used_byte = SPIFFS.usedBytes();
      if (total_byte - used_byte < 400) {
        //Кончилось место, удалим старый файл. Надо было сохранять раньше
        if (SPIFFS.exists("/data_old.csv")) {
          SPIFFS.remove("/data_old.csv");
        }
      }
      vTaskDelay(10 / portTICK_PERIOD_MS);
      if (total_byte - used_byte < 50) {
        SendMsg("Заканчивается память! Всего: " + String(total_byte) + ", использовано: " + String(used_byte), ALARM_MSG);
      }
    }

    return str;
  }
  return "";
}
