#include <Settings.h>


    void InitMQTT();
    void loopMQTT();
    void setup_WS();
    void loop_WS();
    void Init_USB_Mass_Storage();
    void ToggleUSBMassStorage();
    bool hasActiveMQTTSessions();
    bool enableBrokerClients();
    void loopWIFI();
    void setupWIFI();
    void setupClock();
    void DbgMsg(const String& Msg, bool ln);
    void SerialMsg(const String& Msg, bool ln);
    void verbose_print_reset_reason();
    void read_config();
    void SetupServerInit(void);

inline String format_float(float v, int d) {
    char outstr[15];
    dtostrf(v, 1, d, outstr);
    return outstr;
}
void RotateDisplay() {
    if (dispRotate) tft.setRotation(1);
    else tft.setRotation(3);
    dispRotate = !dispRotate;
    prefs.begin("device-config", false);
    prefs.putBool("dispRotate", dispRotate);
    prefs.end();
    tft.fillScreen(TFT_BLACK);
}
String Card_Str() {
    float free = (SD_MMC.totalBytes() - SD_MMC.usedBytes());
    String freeS = "";
    uint8_t cardType = SD_MMC.cardType();
    String CardStr;
    if (cardType != CARD_NONE) {
        uint64_t card_size_bytes = SD_MMC.cardSize();
        float sdCardSize;
        if (card_size_bytes >= (uint64_t)1024 * 1024 * 1024) {
            sdCardSize = (float)card_size_bytes / (1024.0 * 1024.0 * 1024.0);
            CardStr = "SD:" + String(sdCardSize) + " GB";
        } else {
            sdCardSize = (float)card_size_bytes / (1024.0 * 1024.0);
            CardStr = "SD:" + String(sdCardSize) + " MB";
        }
        if (free > 1024 * 1024) {
            CardStr += " Free: " + format_float(free / (1024 * 1024 * 1024), 1) + " GB";
        } else if (free > 1024 * 1024) {
            CardStr += " Free: " + format_float(free / (1024 * 1024), 1) + " MB";
        } else if (free > 1024) {
            CardStr += " Free: " + format_float(free / 1024, 1) + " KB";
        } else {
            CardStr += " Free: " + String(free) + " B"; 
        }

    } else {
        CardStr = "SD:N.A";
    }
    return CardStr;
}
String WiFi_Status() {
    if (WiFi.isConnected()) return WiFi.localIP().toString() + " RSSI:" + String(WiFi.RSSI());
                        else return "Connect to WiFi...";    
}
void InitSD() {
        // ================ Initialize SD card =================
    SD_MMC.setPins(SD_MMC_CLK_PIN, SD_MMC_CMD_PIN, SD_MMC_D0_PIN, SD_MMC_D1_PIN, SD_MMC_D2_PIN, SD_MMC_D3_PIN);
    if (!SD_MMC.begin()) {
        Serial.println("Card Mount Failed");
    } else sdEnable = true;
    uint8_t cardType = SD_MMC.cardType();
    if (cardType != CARD_NONE) {
        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");
        }
        Serial.printf("SD_MMC Card Size: %llu bytes\n", SD_MMC.cardSize());
    }
}

void DisplayTFTInfo() {
    tft.setTextColor(TFT_BLUE, TFT_BLACK);
    tft.setCursor (8, 10);
    tft.print(WiFi_Status());
    static uint32_t SDPrintTime = millis() + 10000;
    if ( millis() - SDPrintTime > 10000) {
        SDPrintTime = millis();

        tft.setTextColor(TFT_SILVER, TFT_BLACK);
        tft.setCursor (8, 70);
        tft.print(Card_Str());
    }
    if (hasActiveMQTTSessions()) tft.setTextColor(TFT_RED, TFT_BLACK);//цвет часов в зависимости от статуса логгера
    else if (enableBrokerClients()) tft.setTextColor(TFT_GREEN, TFT_BLACK);
    else tft.setTextColor(TFT_GOLD, TFT_BLACK);

    tft.setCursor (5, 32);
    tft.setTextSize(3);
    if (WiFi.isConnected()) tft.print(NTP.getFormattedTime());
                        else tft.print("-=TIME=-");
    tft.setTextSize(1);
    
}
void DisplayLQInfo() { //Liquid cristal 4*20
    LQ.setCursor(0,0);LQ.print(NTP.getFormattedTime());
    LQ.setCursor(0,2);LQ.print(WiFi_Status());
    LQ.setCursor(0,3);LQ.print(Card_Str());
}
void DisplayLDInfo() { //OLED 128*64
    String a = NTP.getFormattedTime();
    String b = WiFi_Status();
    String c = Card_Str();
    LD.printString_12x16(a.c_str(), 1, 1);
    LD.printString_6x8(b.c_str(), 1, 6);
    LD.printString_6x8(c.c_str(), 1, 7);
}
void DisplayInfo() { 
    switch(RegSetup.disp) {
        case 1: { // TFT t-dongle
            DisplayTFTInfo();
            break;
        }
        case 2: { //Liquid cristal 4*20
            DisplayLQInfo();
            break;
        }
        case 3: { //OLED 128*64
            DisplayLDInfo();
            break;
        }
    }
}

void InitDisplay() {
    switch(RegSetup.disp) {
        case 1: { // TFT t-dongle
            tft.init();
            if (dispRotate) tft.setRotation(3); else tft.setRotation(1);
            digitalWrite(TFT_LEDA_PIN, 0);
            tft.setTextFont(1);
            tft.fillScreen(TFT_BLACK);
            tft.setTextColor(TFT_YELLOW, TFT_BLACK); // Note: the new fonts do not draw the background colour 
            Serial.println("TFT initialized");
            break;
        }
        case 2: { //Liquid cristal 4*20
            LQ.init();
            LQ.begin(20, 4);
            LQ.backlight();
            LQ.clear();
            Serial.println("Liquid Cristal initialized");
            break;
        }
        case 3: { //OLED 128*64
            LD.init();
            for (uint8_t i = 0; i < 8; i++) 
            LD.printString_6x8(F("                     "), 1, i); //очистка дисплея 
            Serial.println("OLED initialized");
            break;
        }
        default:
            Serial.println("No LCD");
            return;
    }    
}
void MassStorageOn() {
    ToggleUSBMassStorage();
}
void setup() {
    pinMode(TFT_LEDA_PIN, OUTPUT);
    pinMode(BOOT_PIN, INPUT);
    button.attachClick(RotateDisplay);
    button.attachLongPressStop(MassStorageOn); // Длинное нажатие для переключения USB

    Serial.begin(115200);
    Serial.setTimeout(15);
    Serial.println();
    read_config();
    InitDisplay();
    FastLED.addLeds<APA102, LED_DI_PIN, LED_CI_PIN, BGR>(&leds, 1);
    FastLED.setBrightness(100);
    delay(1500);
    verbose_print_reset_reason();
    // Инициализация LittleFS для внутренней памяти
    if (!LittleFS.begin(true, "/littlefs", 10, "littlefs")) {
        Serial.println("LittleFS Mount Failed");
        BrokenFS = true;
    } else {
        Serial.println("LittleFS mounted successfully");
        BrokenFS = false;
    }
    
    InitSD();
    DisplayInfo();
    setupWIFI();
    setup_WS();
    setupClock();
    InitMQTT();
    InitOTA();
    leds[0] = CRGB::Blue; // Индикатор нормального режима
    FastLED.show();
    Serial.printf("SD total: %llu bytes, used: %llu bytes\n", SD_MMC.totalBytes(), SD_MMC.usedBytes());
}

void loop() {
    loopWIFI();
    button.tick();
    if (RegSetup.UseMQTT) loopMQTT();
    if (RegSetup.OTA) ArduinoOTA.handle();
    static bool USB_MS_enable = false;
    
    static uint32_t targetTime = millis();
    if ( millis() - targetTime > 1000) {
        targetTime = millis();
        DisplayInfo();        
    }
    
    if (WiFi.isConnected()) {
        NTP.update();        
    }

    if (millis() - rgb_change_interval > 50) {
        rgb_change_interval = millis();
        leds = CHSV(rgb_hue++, 0XFF, 100);
        FastLED.show();
    }
    
    loop_WS();
    delay(5);
}
