/************************************
 Configuration et handlers du server
************************************/

/**
 * @brief Type de la variable globale command
 *
 */
struct command_t
{
    bool running; // Une commande doit être exécutée
    bool stopped; // La commande doit être stoppée
    String name;  // Nom de la commande
    int value;    // Valeur (nombre de pas à effectuer)
};

/**
 * @brief Met à jour la command globale.
 * @internal
 *
 * @param commandName Nom de la nouvelle commande.
 * @param commandValue Valeur de la nouvelle commande.
 * @param globalCommand Commande globale (courante).
 */
void setGlobals(String commandName, float commandValue, command_t &globalCommand)
{
    // Assert command before updating globals
    if (commandName != "forward" && commandName != "backward" && commandName != "left" && commandName != "right")
    {
        return;
    }

    // Update globals
    globalCommand.name = commandName;
    globalCommand.running = true;
    globalCommand.stopped = false;
    globalCommand.value = convertLengthToSteps(commandValue);
}

/**
 * @brief Lorsqu'une commande arrive au serveur, cette fonction permet.
 * @internal
 *
 * @param commandName Nom de la commande.
 * @param commandValue Valeur de la command (si 0 assigné à 474).
 */
void requestCheck(String commandName, float commandValue, command_t &globalCommand)
{
    if (commandName == "stop")
    {
        globalCommand.name = "stop";
        globalCommand.running = true;
        globalCommand.stopped = true;
    }
    else
    {
        setGlobals(commandName, commandValue, globalCommand);
    }

    if (commandValue == 0)
    {
        globalCommand.value = 474;
    }
}

/**
 * @brief Parse la requête GET (vers "/get") du serveur et résout le nom de la commande et sa valeur.
 *
 * Exemple :
 * ```
 * String commandName;
 * float commandValue;
 * parseRequestParams(request, commandName, commandValue);
 * ```
 *
 * @param request Requête contenant la commande.
 * @param commandName Nom de la commande à assigner.
 * @param commandValue Valeur de la commande à assigner.
 * @param globalCommand Commande globale (courante) à mettre à jour.
 *
 */
void parseRequestParams(AsyncWebServerRequest *request, String &commandName, float &commandValue, command_t &globalCommand)
{
    // Stop here with error message if wrong command
    if (!request->hasParam("command"))
    {
        commandName = "No command provided";
        return;
    }

    // Update command from params
    commandName = request->getParam("command")->value();

    // Update value from params and use "0" as default
    commandValue = request->hasParam("value") ? request->getParam("value")->value().toFloat() : 0;

    requestCheck(commandName, commandValue, globalCommand);
}

/**
 * @brief Configuration du serveur asynchrone.
 *
 * @param server Serveur à configurer.
 * @param globalCommand Commande globale (courante) à mettre à jour lors des requêtes.
 */
void serverConfig(AsyncWebServer &server, command_t &globalCommand)
{
    server.on("/get", HTTP_GET, [&globalCommand](AsyncWebServerRequest *request)
              {
    String commandName;
    float commandValue;

    // Parse request params and update command and value
    parseRequestParams(request, commandName, commandValue, globalCommand);

    Serial.print(commandName);
    Serial.print(": ");
    Serial.println(commandValue);
    request->send(200, "text/plain", commandName); });
}

/**
 * @brief Démarre le point d'accès WiFi.
 *
 * @param WiFi WiFi à configurer.
 */
void connectWiFi(WiFiClass &WiFi)
{
    // For simulator only
    WiFi.mode(WIFI_STA);
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    if (WiFi.waitForConnectResult() != WL_CONNECTED)
    {
        Serial.printf("WiFi Failed!\n");
        return;
    }
    Serial.println(" Connected!");

    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());

    // WiFi.mode(WIFI_AP);
    // WiFi.softAP(WIFI_SSID, WIFI_PASSWORD);
    // Serial.print("[+] AP Created with IP Gateway ");
    // Serial.println(WiFi.softAPIP());
    // Serial.println("");
}