#ifndef aclwebserver_h
#define aclwebserver_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 "hardware.h"
#include <ArduinoJson.h>
#include <AsyncJson.h>

class ACLWebServerClass{

    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("/users", HTTP_GET, [&](AsyncWebServerRequest *request){

                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                // Create a JSON array to store the users
                DynamicJsonDocument jsonDoc(ESP.getMaxAllocHeap());
                JsonArray usersArray = jsonDoc.to<JsonArray>();

                // Retrieve the ACL data using the getter function
                const User* aclData = acl.getACL();

                // Iterate over each user in the ACL and add it to the JSON array
                for (int i = 0; i < acl.getACLSize(); i++) {
                JsonObject user = usersArray.createNestedObject();
                user["cardId"] = aclData[i].cardId;
                user["desc"] = aclData[i].desc;
                }

                // Convert the JSON array to a string
                String response;
                serializeJson(usersArray, response);

                // Set the response content type to JSON
                request->send(200, "application/json", response);
            });

            _server->on("/users/create", HTTP_POST, [&](AsyncWebServerRequest *request){
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                
                if(request->hasParam("cardId", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}");
                request->send(response); 
                }

                if(request->hasParam("desc", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}");
                request->send(response); 
                }

                String cardId = String(request->arg("cardId"));
                String desc = String(request->arg("desc"));


                if (!cardId.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"cardId May not be Empty.\"}");
                    request->send(response); 
                }


                if (!desc.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"desc May not be Empty.\"}");
                    request->send(response); 
                }


                if (acl.validateAccess(String(cardId))) {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Duplicate ACL\"}");
                request->send(response); 
                } else {
                acl.addUser(cardId, desc);
                acl.saveToEEPROM();
                request->send(201); // Create
                }
            });

            _server->on("/users/update", HTTP_POST, [&](AsyncWebServerRequest *request){
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }

                if(request->hasParam("cardId", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}");
                request->send(response); 
                }
                
                if(request->hasParam("newCardId", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "\"msg\":\"No newCardId\"}");
                request->send(response); 
                }

                if(request->hasParam("desc", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}");
                request->send(response); 
                }
                String cardId = String(request->arg("cardId"));
                String newCardId = String(request->arg("newCardId"));
                String desc = String(request->arg("desc"));



                if (!cardId.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"cardId May not be Empty.\"}");
                    request->send(response); 
                }

                if (!newCardId.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"newCardId May not be Empty.\"}");
                    request->send(response); 
                }

                if (!desc.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"desc May not be Empty.\"}");
                    request->send(response); 
                }

                acl.updateUser(cardId, newCardId, desc);
                acl.saveToEEPROM();
                request->send(201); // Created
            });

            _server->on("/users/remove", HTTP_POST, [&](AsyncWebServerRequest *request){
                if(_authRequired){
                    if(!request->authenticate(_username.c_str(), _password.c_str())){
                        return request->requestAuthentication();
                    }
                }
                
                if(request->hasParam("cardId", true)) {}  //This is important, otherwise the sketch will crash if there is no body
                else {
                AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}");
                request->send(response); 
                }
                String cardId = String(request->arg("cardId"));


                if (!cardId.length() > 0 ) {
                    AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"cardId May not be Empty.\"}");
                    request->send(response); 
                }

                acl.removeUser(cardId);
                acl.saveToEEPROM();
                request->send(201); // Created
                });
            }

        // 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 "";
                }
            }
};

ACLWebServerClass ACLWebServer;
#endif