#include <setup_server.h>

#include <html/first_connection_page.h>

#ifdef _DEBUG
#define _DEBUG_PRINT(x) utils::debug_print(x)
#else
#define _DEBUG_PRINT(x)
#endif

setup_server::setup_server()
    : server(new ESP8266WebServer(80))
{
    server->on("/", [this] { this->root_callback(); });
    server->on("/submit", HTTP_POST, [this] { this->ap_submission_callback(); });

    server->onNotFound([this] { this->not_found_callback(); });
    server->begin();

    _DEBUG_PRINT(std::string("Server Started"));
}

setup_server::~setup_server()
{
    delete server;
}

setup_server::SetupErrorCodes setup_server::get_connection(const std::string &ssid, const std::string &password)
{
    auto ret = SetupErrorCodes::CONNECTION_ERROR;
    serverConnection = false;
    WiFi.mode(WIFI_AP_STA);
    if (WiFi.softAP(AP_SSID, AP_PASSWORD))
    {
        _DEBUG_PRINT(std::string("Soft AP Ready"));
        _DEBUG_PRINT("IP address: " + WiFi.localIP().toString());

        while (!serverConnection)
        {
            server->handleClient();
            delay(10);
        }

        // We connected!
        WiFi.softAPdisconnect();
        WiFi.mode(WIFI_STA);
        WiFi.setAutoConnect(true);
        WiFi.setAutoReconnect(true);
        ret = SetupErrorCodes::SUCCESS;
    }

    _DEBUG_PRINT(std::string("Soft AP off, setup complete"));
    return ret;
}

uint8_t setup_server::connect_to_ap(const std::string &ssid, const std::string &password)
{
    _DEBUG_PRINT("Connecting " + ssid + ":" + password);
    WiFi.begin(ssid.c_str(), password.c_str());
    auto ret = WiFi.waitForConnectResult();
    return ret;
}

void setup_server::root_callback()
{
    _DEBUG_PRINT("Request \"/\" from " + server->client().remoteIP().toString());
    auto pageSize = strlen_P(first_connection_page);
    auto outBuffer = new char[pageSize + 1];
    strncpy_P(outBuffer, first_connection_page, pageSize);
    outBuffer[pageSize] = '\0';
    server->send(200, "text/html", outBuffer);
    delete[] outBuffer;
}

void setup_server::ap_submission_callback()
{
    _DEBUG_PRINT("Request \"/submit\" from " + server->client().remoteIP().toString());
    auto ssidArg = server->arg("ssid");
    auto passwordArg = server->arg("password");
    if (ssidArg != NULL && passwordArg != NULL)
    {
        auto ssid = std::string(ssidArg.c_str());
        auto password = std::string(passwordArg.c_str());
        auto ret = connect_to_ap(ssid, password);
        if (ret == WL_CONNECTED)
        {
            server->send(200, "text/plain", "Success");
            serverConnection = true;
        }
        else
        {
            server->send(500, "text/plain", "Could not connect");
        }
    }
    else
    {
        server->send(500, "text/plain", "Parameter not set");
    }
}

void setup_server::not_found_callback()
{
    _DEBUG_PRINT("404 NOT FOUND " + server->uri());
    server->send(404, "text/html", "Page not found");
}
