#ifndef mainwebserver_h
#define mainwebserver_h

#include "Arduino.h"
#include "stdlib_noniso.h"
#include "WiFi.h"
#include "AsyncTCP.h"
#include "Update.h"
#include "esp_int_wdt.h"
#include "esp_task_wdt.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include "hardware.h"
#include "settings.h"

class MainWebServerClass{

    public:

        void begin(AsyncWebServer *server, const char* username = "", const char* password = ""){
            _server = server;

            if(strlen(username) > 0){
                _authRequired = true;
                _username = username;
                _password = password;
            }else{
                _authRequired = false;
                _username = "";
                _password = "";
            }

            _server->on("/", HTTP_GET, [&](AsyncWebServerRequest *request){
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
            
                request->send(SPIFFS, "/index.html", String(), false, processor);
            });

            _server->onNotFound([&](AsyncWebServerRequest *request){
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                request->send(200, "application/json", "{\"msg\":\"The content you are looking for was not found\"}");
            });

            _server->on("/gpio", HTTP_GET, [&] (AsyncWebServerRequest *request) {
                String paramOutput;
                String paramState;

                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }

                // GET input1 value on <ESP_IP>/gpio?output=<paramOutput>&state=<paramState>
                if (request->hasParam("output") && request->hasParam("state")) {
                paramOutput = request->getParam("output")->value();
                paramState = request->getParam("state")->value();

                #ifdef RELAY1
                if (paramOutput == "relay1") {
                    if (paramState  == String(0)){
                        unlockDoor(false);
                        AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Unlocked.\"}");
                        request->send(response); 
                    }
                    else if (paramState  == String(1)) {
                        lockDoor();
                        AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Locked.\"}");
                        request->send(response); 
                    }
                    else {
                        AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Incorect state provide 0 to unlock and 1 to lock.\"}");
                        request->send(response); 
                    }
                }

                
                #endif
                
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Error with request, incorrect GPIO pin number.\"}");
                request->send(response); 

                }
            });

            #ifdef RELAY1
            _server->on("/state/relay1", HTTP_GET, [&] (AsyncWebServerRequest *request) {
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"state\":\""+stateDoor()+"\"}");
                request->send(response); 
            });
            #endif

            _server->on("/settings/get/DoorDisabled", HTTP_GET, [&] (AsyncWebServerRequest *request) {
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"value\":\""+String(settings.DoorDisabled())+"\"}");
                request->send(response); 
            });

            _server->on("/settings/set/DoorDisabled", HTTP_GET, [&] (AsyncWebServerRequest *request) {
                String value;

                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                
                if (request->hasParam("value")) {
                value = request->getParam("value")->value();
                if (value == "0") {
                    settings.setDisableDoor(0);
                    AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 0\"}");
                    request->send(response); 
                }
                else if (value =="1") {
                    settings.setDisableDoor(1);
                    AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 1\"}");
                    request->send(response); 

                } else {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"value should be 0 or 1\"}");
                    request->send(response); 
                }
                }
                else  {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Missing 'value' param.\"}");
                request->send(response); 
                }
            });
        }

        // deprecated, keeping for backward compatibility
        void loop() {
        }
        
    private:
        AsyncWebServer *_server;
        String _username = "";
        String _password = "";
        bool _authRequired = false;

        static String outputState(int output){
                if(digitalRead(output)){
                return "checked";
                }
                else {
                return "";
                }
            }

        // Replaces placeholder with button section in your web page
        static String processor(const String& var){
        //Serial.println(var);
        if(var == "BUTTONPLACEHOLDER"){
            String buttons = "";

            #ifdef RELAY1
            buttons += "<h4>Output - Relay 1 </h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"relay1\" " + MainWebServerClass::outputState(RELAY1_PIN) + "><span class=\"slider\"></span></label>";
            #endif

            return buttons;
        }
        return String();
        }


};

MainWebServerClass MainWebServer;
#endif