#include "WifiManager.h"
#include "Logger.h"

void WifiManager::begin(const String &hostname, const String & wifiStaModeName)
{
  hostname_ = hostname;
  wifiStaModeName_ = wifiStaModeName;
  prefs_.begin("st_wifi_manager");
  startWifi();
}

void WifiManager::startWifi()
{
  WiFi.disconnect();

  const String apPassword = prefs_.getString("apPassword", "");
  const String staSSID = prefs_.getString("staSSID", "");
  const String staPassword = prefs_.getString("staPassword", "");

  if (staSSID.length() > 0 && staPassword.length() > 0)
  {
    // station mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(staSSID.c_str(), staPassword.c_str());
    LOG_INFO("Starting WiFi station mode to ssid %s, hostname %s", staSSID.c_str(), hostname_.c_str());
    WiFi.setHostname(hostname_.c_str());
    int connectCounter = 0;
    bool successful = true;
    delay(5000);

    while (WiFi.status() != WL_CONNECTED)
    {
      LOG_INFO("WiFI connection problem %d", WiFi.status());
      WiFi.begin(staSSID.c_str(), staPassword.c_str());

      connectCounter += 1;
      if (connectCounter >= 60) // for two minutes no connection
      {
        successful = false;
        break; // fallback to AP mode
      }
      delay(5000);
    }
    state_ = STA;
    if (successful)
      return;
  }

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(IPAddress(192, 168, 42, 1), IPAddress(192, 168, 42, 1), IPAddress(255, 255, 255, 0));
  WiFi.softAPsetHostname(hostname_.c_str());

  if (apPassword.length() > 0)
  {
    LOG_INFO("Secured AP mode, name %s\n", wifiStaModeName_.c_str());
    WiFi.softAP(wifiStaModeName_.c_str(), apPassword.c_str());
    state_ = AP_SECURE;
  }
  else
  {
    LOG_INFO("Provisioning AP mode, name %s\n", wifiStaModeName_.c_str());
    WiFi.softAP(wifiStaModeName_.c_str());
    state_ = AP_PROVISIONING;
  }
}

void WifiManager::setStaCredentials(const char *wifiName, const char *password)
{
  assert(state_ != INVALID);

  prefs_.putString("staSSID", wifiName);
  prefs_.putString("staPassword", password);
}

void WifiManager::setApCredentials(const char *password)
{
  assert(state_ != INVALID);

  prefs_.remove("staSSID");
  prefs_.remove("staPassword");
  prefs_.putString("apPassword", password);
}

void WifiManager::resetToApProvisioning()
{
  prefs_.remove("apPassword");
  prefs_.remove("staSSID");
  prefs_.remove("staPassword");
}

void WifiManager::iteration()
{
  if (state_ == STA && WiFi.status() != WL_CONNECTED)
  {
    startWifi();
    LOG_WARNING("Connection lost - Restarting WIFI");
  }
}

const char *WifiManager::stateToString(WifiManager::State state)
{
  switch (state)
  {
  case INVALID:
    return "INVALID";
  case STA:
    return "STATION_MODE";
  case AP_PROVISIONING:
    return "AP_PROVISIONING";
  case AP_SECURE:
    return "AP_SECURE";
  default:
    return "";
  };
}