// Переменные для хранения состояния
String inputString = "";
bool stringComplete = false;
bool apMode = false;

//------------Сеть
  extern "C" {
  #include "esp_wifi.h"
  }
  void PauseForConnect(int timeout = 15000) {
    uint32_t startTime = millis();
    while (WiFi.status() != WL_CONNECTED && millis() - startTime < timeout) {
      Serial.print(".");
      delay(500);
    }
  }
  String current_pass;
  bool connectToWiFi(const char* ssid, const char* password, const char* attemptName, int timeout = 15000) {
      Serial.print(attemptName);
      Serial.println(ssid);
      //Serial.println(password);
      WiFi.disconnect(true);
      delay(1000);
      WiFi.mode(WIFI_OFF);
      delay(500);
      WiFi.mode(WIFI_STA);
      WiFi.persistent(false);
      WiFi.begin(ssid, password);
      PauseForConnect(timeout);
      WiFi.persistent(true);
      Serial.println();
      if (WiFi.status() == WL_CONNECTED) current_pass = String(password);
      return (WiFi.status() == WL_CONNECTED);
  }
  // Максимальное количество сетей
  #define MAX_NETWORKS 10

  struct WiFiNetwork {
      char ssid[33];      // Максимум 32 символа для SSID
      char password[33];  // Максимум 32 символа для пароля
      int32_t rssi;
      bool configured;
      bool available;
  };
  
  WiFiNetwork* networks = nullptr;// Динамическое выделение памяти
  int networkCount = 0;


  int parseWiFiConfig() {// Функция для парсинга wifi.ini
      // Освобождаем предыдущую память
      if (networks != nullptr) {
          delete[] networks;
          networks = nullptr;
      }
      networkCount = 0;
      if (!getActiveFS().exists("/wifi.ini")) {
          Serial.println("wifi.ini not found");
          return 0;
      }
      File file = getActiveFS().open("/wifi.ini", "r");
      if (!file) {
          Serial.println("Failed to open wifi.ini");
          return 0;
      }
      // Сначала посчитаем количество сетей в файле
      int tempCount = 0;
      while (file.available()) {
          String line = file.readStringUntil('\n');
          line.trim();
          if (line.length() == 0 || line.startsWith("#")) {
              continue;
          }
          int separatorPos = line.indexOf(' ');
          if (separatorPos > 0) {
              tempCount++;
          }
      }
      if (tempCount == 0) {
          file.close();
          return 0;
      }
      // Ограничиваем максимальным количеством
      networkCount = (tempCount > MAX_NETWORKS) ? MAX_NETWORKS : tempCount;
      // Выделяем память только под нужное количество сетей
      networks = new WiFiNetwork[networkCount];
      if (networks == nullptr) {
          Serial.println("Failed to allocate memory for networks");
          file.close();
          networkCount = 0;
          return 0;
      }
      // Возвращаемся к началу файла
      file.seek(0);
      int index = 0;
      while (file.available() && index < networkCount) {
          String line = file.readStringUntil('\n');
          line.trim();
          if (line.length() == 0 || line.startsWith("#")) {
              continue;
          }
          int separatorPos = line.indexOf(' ');
          if (separatorPos > 0) {
              String ssidStr = line.substring(0, separatorPos);
              String passStr = line.substring(separatorPos + 1);
              if (ssidStr.length() > 0 && ssidStr.length() <= 32) {
                  // Копируем в структуру
                  ssidStr.toCharArray(networks[index].ssid, 
                                    sizeof(networks[index].ssid));
                  passStr.toCharArray(networks[index].password, 
                                    sizeof(networks[index].password));
                  networks[index].rssi = -1000;
                  networks[index].configured = true;
                  networks[index].available = false;
                  index++;
                  Serial.printf("Found network #%d: %s\n", index, ssidStr.c_str());
              }
          }
      }
      file.close();
      Serial.printf("Parsed %d networks from wifi.ini\n", networkCount);
      return networkCount;
  }
  // Функция высвобождения памяти
  void freeNetworksMemory() {
      if (networks != nullptr) {
          delete[] networks;
          networks = nullptr;
      }
      networkCount = 0;
  }
  // Функция сканирования сетей (используется только если сетей > 1)
  bool scanSpecificNetworks() {
      Serial.println("Starting targeted WiFi scan...");
      // Сбрасываем флаги доступности
      for (int i = 0; i < networkCount; i++) {
          networks[i].available = false;
          networks[i].rssi = -1000;
      }
      // Для каждой сети выполняем целевое сканирование
      int foundCount = 0;
      for (int i = 0; i < networkCount; i++) {
          // Сканируем конкретную сеть
          int scanResult = WiFi.scanNetworks(false, false, false, 300, 0, networks[i].ssid);
          if (scanResult == 1) {
              // Найдена искомая сеть
              networks[i].rssi = WiFi.RSSI(0);
              networks[i].available = true;
              foundCount++;
              Serial.printf("✓ Found: %s (RSSI: %d dBm)\n", 
                          networks[i].ssid, networks[i].rssi);
          } else if (scanResult == 0) {
              // Сеть не найдена
              Serial.printf("✗ Not found: %s\n", networks[i].ssid);
          } else if (scanResult < 0) {
              // Ошибка сканирования
              Serial.printf("! Scan error for %s: %d\n", networks[i].ssid, scanResult);
          }
          // Очищаем результаты после каждого сканирования
          WiFi.scanDelete();
          // Небольшая пауза между сканированиями
          if (i < networkCount - 1) {
              delay(100);
          }
      }
       Serial.printf("Targeted scan complete. Found %d/%d networks\n", foundCount, networkCount);
      return (foundCount > 0);
  }
  // Простая сортировка по RSSI (используется только если сетей > 1)
  void sortNetworksByRSSI() {
      // Сортировка пузырьком
      for (int i = 0; i < networkCount - 1; i++) {
          for (int j = i + 1; j < networkCount; j++) {
              // Сначала доступные сети, потом недоступные
              bool iAvailable = networks[i].available;
              bool jAvailable = networks[j].available;
              if ((!iAvailable && jAvailable) || 
                  (iAvailable && jAvailable && networks[j].rssi > networks[i].rssi)) {
                  // Меняем местами
                  WiFiNetwork temp = networks[i];
                  networks[i] = networks[j];
                  networks[j] = temp;
              }
          }
      }
  }
  // Подключение к одной сети 
  bool connectToSingleWiFi() {
      if (networkCount != 1 || networks == nullptr) {
          return false;
      }
      Serial.println("\n=== Single Network Connection ===");
      Serial.printf("Attempting to connect to: %s\n", networks[0].ssid);
      if (connectToWiFi(networks[0].ssid, networks[0].password, "Single network: ", 15000)) {
          Serial.printf("✓ Success! Connected to: %s\n", networks[0].ssid);
          Serial.printf("  IP Address: %s\n", WiFi.localIP().toString().c_str());
          return true;
      }
      Serial.printf("✗ Failed to connect to: %s\n", networks[0].ssid);
      return false;
  }
  // Функция подключения к лучшей сети (для 2+ сетей)
  bool connectToBestWiFiMultiple() {
      if (networkCount < 2) {
          return false;
      }
      Serial.println("\n=== Smart WiFi Connection (Multiple Networks) ===");
      // Сканируем сети
      bool scanSuccess = scanSpecificNetworks();
      // Сортируем сети (доступные с лучшим RSSI первыми)
      sortNetworksByRSSI();
      // Пробуем подключиться к найденным сетям
      for (int i = 0; i < networkCount; i++) {
          if (!networks[i].available) {
              continue;
          }
          Serial.printf("\n[%d/%d] Connecting to: %s (RSSI: %d dBm)\n", 
                      i+1, networkCount, networks[i].ssid, networks[i].rssi);
          String attemptName = String("WiFi ") + String(i+1) + ": ";
          if (connectToWiFi(networks[i].ssid, networks[i].password, attemptName.c_str(), 15000)) {
              Serial.printf("✓ Success! Connected to: %s\n", networks[i].ssid);
              Serial.printf("  IP Address: %s\n", WiFi.localIP().toString().c_str());
              return true;
          }
          Serial.printf("✗ Failed to connect to: %s\n", networks[i].ssid);
          delay(2000);
      }
      
      // Если не нашли сети при сканировании, пробуем прямое подключение
      Serial.println("\nNo networks found during scan, trying direct connection...");
      
      for (int i = 0; i < networkCount; i++) {
          Serial.printf("\nDirect attempt %d/%d: %s\n", 
                      i+1, networkCount, networks[i].ssid);
          
          String attemptName = String("Direct ") + String(i+1) + ": ";
          
          if (connectToWiFi(networks[i].ssid, networks[i].password, attemptName.c_str(), 10000)) {
              Serial.printf("✓ Direct connection successful: %s\n", networks[i].ssid);
              return true;
          }
          delay(1000);
      }
      
      Serial.println("Failed to connect to any configured network");
      return false;
  }
  // Основная функция автоподключения
  bool autoConnectToWiFi() {
      Serial.println("\n=== Auto WiFi Connection ===");
      // 1. Читаем конфигурацию
      if (parseWiFiConfig() == 0) {
          Serial.println("No networks in wifi.ini");
          return false;
      }
      bool connected = false;
      // 2. В зависимости от количества сетей выбираем стратегию
      if (networkCount == 1) {
          // Для одной сети - сразу подключаемся
          connected = connectToSingleWiFi();
      } else {
          // Для нескольких сетей - сканируем и выбираем лучшую
          connected = connectToBestWiFiMultiple();
      }
      // 3. Освобождаем память после использования
      freeNetworksMemory();
      return connected;
  }
  void InitWiFi(bool wifiAP) {
    if (!wifiAP) {// изо всех сил пытаемся подключиться к wi-fi
        WiFi.mode(WIFI_STA);
        WiFi.setSleep(WIFI_PS_NONE);
        WiFi.setHostname(HOST);
        WiFi.setAutoReconnect(true);
        bool connected = false;

        // 1. Автоподключение из wifi.ini со сканированием
        Serial.println("Attempt 1: Auto-connect from wifi.ini");
        connected = autoConnectToWiFi();
        
        // 2. Попытка с сетью из Setup
        if (!connected && RegSetup.SavedSSID != "") {
            Serial.println("Attempt 2: Setup.htm network");
            connected = connectToWiFi(RegSetup.SavedSSID, RegSetup.SavedPASS, 
                                     "Connecting to Setup WiFi ");
        }
        // 3. Стандартная попытка (последняя сохраненная)
        if (!connected) {
            Serial.println("Attempt 3: Previous WiFi connection");
            WiFi.begin(); // Пробуем предыдущее подключение
            PauseForConnect(10000);
            connected = (WiFi.status() == WL_CONNECTED);
        }
        // 4. Попытка с сетью по умолчанию
        if (!connected) {
            Serial.println("Attempt 4: Default network");
            connected = connectToWiFi(WIFI_SSID, WIFI_PASSWORD, 
                                     "Connecting to INI.h WiFi ");
        }
        
        if (connected) {
            // Отображение информации о подключении
            Serial.println();
            Serial.print(F("Connected to ")); 
            Serial.println(WiFi.SSID());    
            Serial.print(F("IP ")); 
            Serial.println(WiFi.localIP().toString());   
        }
    }
    // Если не удалось подключиться, запускаем AP режим
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("All connection attempts failed, starting AP mode");
        WiFi.setAutoReconnect(false); 
        WiFi.mode(WIFI_AP);
        WiFi.softAP(HOST, WiFiAP_Pass);
        Serial.println();
        Serial.println(F("Started as WiFi AP"));
        Serial.print("Name: " + String(HOST) + ", Pass: " + String(WiFiAP_Pass)); 
        Serial.println(F(",IP: 192.168.4.1"));
    } else {
        WiFi.setAutoReconnect(true); 
    }
  }
  void reset_wifi() {
    WiFi.disconnect(true);
    vTaskDelay(200/portTICK_PERIOD_MS);
    //Сбрасываем сохраненные настройки WiFi и переподключаемся
    InitWiFi(false);
  }
  void InitOTA() {
    if (true) {
        ArduinoOTA.setHostname(HOST);
        ArduinoOTA.begin(); 
    }
  }

void setupWIFI() {
  InitWiFi(false);
    /*WiFi.setSleep(WIFI_PS_NONE);
    WiFi.setHostname("Logger");
    WiFi.setAutoReconnect(true);
    WiFi.persistent(true);
    WiFi.begin();//Используем прошлое успешное подключение
      // Ждем подключения (таймаут 10 секунд)
    int attempts = 0;
    while (WiFi.status() != WL_CONNECTED && attempts < 20) {
        delay(500);
        Serial.print(".");
        attempts++;
    }
    if (WiFi.status() != WL_CONNECTED) {// Не удалось?
        Serial.println("No stored config");
        WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // Подключаемся с дефолтными параметрами
    } else {
        Serial.println("Using stored WiFi config");
    }*/
  Serial.println();
  Serial.println("ESP32-S3 WiFi configurator started");
  Serial.println("Commands:");
  Serial.println("  wifi SSID PASSWORD - Connect to WiFi");
  Serial.println("  wifi=ap [SSID] [PASSWORD] - Switch to Access Point mode (optional SSID and password)");
  Serial.println();
}
void loopWIFI() {
  // Обработка входящих данных из Serial
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    parseCommand(cmd);
  }
}
// Функция парсинга команды
void parseCommand(String command) {
  command.trim(); // Удаляем пробелы в начале и конце
  
  Serial.print("Received command: ");
  Serial.println(command);
  
  // Проверяем команду переключения в режим точки доступа
  if (command.startsWith("wifi=ap")) {
    parseAPCommand(command);
    return;
  }
  
  // Проверяем команду подключения к WiFi
  if (command.startsWith("wifi ")) {
    // Удаляем префикс "WIFI "
    String params = command.substring(5);
    params.trim();
    
    // Ищем первый пробел для разделения SSID и пароля
    int spaceIndex = params.indexOf(' ');
    
    if (spaceIndex > 0) {
      String ssid = params.substring(0, spaceIndex);
      String password = params.substring(spaceIndex + 1);
      
      ssid.trim();
      password.trim();
      
      if (ssid.length() > 0 && password.length() > 0) {
        connectToWiFi(ssid, password);
      } else {
        Serial.println("Error: SSID or password is empty");
      }
    } else {
      Serial.println("Error: Invalid format. Use: WIFI SSID PASSWORD");
    }
  } else {
    Serial.println("Unknown command. Use:");
    Serial.println("  WIFI SSID PASSWORD - Connect to WiFi");
    Serial.println("  WIFI=AP [SSID] [PASSWORD] - Switch to Access Point mode");
  }
}
// Функция парсинга команды для режима точки доступа
void parseAPCommand(String command) {
  // Удаляем префикс "WIFI=AP"
  String params = command.substring(7); // Длина "WIFI=AP" = 7
  params.trim();
  
  String apSSID = HOST;
  String apPassword = WiFiAP_Pass;
  
  // Если есть параметры
  if (params.length() > 0) {
    // Ищем первый пробел для разделения SSID и пароля
    int spaceIndex = params.indexOf(' ');
    
    if (spaceIndex > 0) {
      // Есть и SSID и пароль
      apSSID = params.substring(0, spaceIndex);
      apPassword = params.substring(spaceIndex + 1);
      
      apSSID.trim();
      apPassword.trim();
      
      // Проверка длины пароля (минимум 8 символов для WPA2)
      if (apPassword.length() > 0 && apPassword.length() < 8) {
        Serial.println("Warning: Password should be at least 8 characters for WPA2");
      }
    } else {
      // Только SSID без пароля
      apSSID = params;
      apSSID.trim();
      apPassword = ""; // Открытая сеть (без пароля)
      Serial.println("Warning: No password provided - creating open network");
    }
  }
  
  enableAPMode(apSSID, apPassword);
}
// Функция подключения к WiFi
void connectToWiFi(String ssid, String password) {
  Serial.println();
  Serial.print("Connecting to WiFi: ");
  Serial.println(ssid);
  
  // Отключаем режим точки доступа если был включен
  if (apMode) {
    WiFi.mode(WIFI_STA);
    apMode = false;
  }
  WiFi.disconnect(false);
  delay(50);
  WiFi.mode(WIFI_OFF);
  delay(50);
  WiFi.mode(WIFI_STA);
  WiFi.persistent(true);
  WiFi.begin(ssid.c_str(), password.c_str());
  
  // Ждем подключения (таймаут 20 секунд)
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 40) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  tft.fillScreen(TFT_BLACK);
  Serial.println();
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi connected successfully!");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("Failed to connect to WiFi");
  }
}
// Функция включения режима точки доступа
void enableAPMode(String ssid, String password) {
  Serial.println();
  Serial.println("Switching to Access Point mode");
  Serial.print("AP SSID: ");
  Serial.println(ssid);
  
  if (password.length() > 0) {
    Serial.print("AP Password: ");
    Serial.println(password);
  } else {
    Serial.println("AP Password: None (open network)");
  }
  WiFi.disconnect(false);
  delay(50);
  WiFi.mode(WIFI_OFF);
  delay(50);
  // Отключаем WiFi клиент и включаем точку доступа
  WiFi.mode(WIFI_AP);
  
  bool apStarted;
  if (password.length() > 0) {
    apStarted = WiFi.softAP(ssid.c_str(), password.c_str());
  } else {
    apStarted = WiFi.softAP(ssid.c_str()); // Открытая сеть
  }
  
  if (apStarted) {
    Serial.println("Access Point started successfully");
    Serial.print("AP IP address: ");
    Serial.println(WiFi.softAPIP());
    apMode = true;
  } else {
    Serial.println("Failed to start Access Point");
  }
}