#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
#include "abc800_config.h"
#include "abc800_web.h"
#include "abc800_func.h"
#include "abc800_webcontent.h"
#include "abc800_hidboot.h"
#include "abc800_gpio.h"
#include <WebSerial.h>
#include "ESPAsyncWiFiManager.h"
static const char TAG[] = __FILE__;

extern WiFiClass WiFi;
extern AsyncWebServer server;
extern abc800::web abc800_web;
extern abc800::std_abc800 abc800_std;
extern TaskHandle_t OTA_Task ;
extern KeyboardReportParser keyparse;
extern QueueHandle_t abc800_key_queue_out;
extern AsyncElegantOtaClass AsyncElegantOTA;
extern DNSServer dns;
extern AsyncWiFiManager wifiManager;
extern AsyncWebSocket ws("/ws");
bool connected2=false;
bool ledState;
 static   void web_onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,void *arg, uint8_t *data, size_t len) {
        switch (type) {
            case WS_EVT_CONNECT:
            ESP_LOGI(TAG,"WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
            connected2 = true;
            break;
            case WS_EVT_DISCONNECT:
            ESP_LOGI(TAG,"WebSocket client #%u disconnected\n", client->id());
            connected2 = false;
            break;
            case WS_EVT_DATA:
            abc800_web.handleWebSocketMessage(arg, data, len);
            break;
            case WS_EVT_PONG:
            case WS_EVT_ERROR:
            break;
        }
 }
namespace abc800
{
    void OTAtask(void * parameter){
        AsyncElegantOTA.loop();
        ws.cleanupClients();
    }
    const char* PARAM_INPUT_1 = "input1";
    const char* PARAM_INPUT_2 = "input2";
    const char* PARAM_INPUT_3 = "input3";
    void WSrecvMsg(uint8_t *data, size_t len){
        String d = "";
        key800queue key800queue;
        uint8_t * decode_data =(uint8_t * ) malloc( len);
        uint8_t length = abc800_std.processutf8String(data,len,decode_data);
        //Serial.println(length);
        for(int i=0; i <= length; i++){
            //Serial.println(decode_data[i]);
            key800queue.ascii = decode_data[i];
            key800queue.special = 0x00;
            key800queue.modifier = 0x00;
            if (xQueueSend(abc800_key_queue_out, (void *)&key800queue, 0) != pdTRUE) {
                ESP_LOGE(TAG,"Queue full");
            }
        }
        key800queue.ascii = 0x13;
        if (xQueueSend(abc800_key_queue_out, (void *)&key800queue, 0) != pdTRUE) {
                ESP_LOGE(TAG,"Queue full");
        }
        for(int i=0; i <len; i++){
            d+= char(data[i]);
        }
        WebSerial.print(d+"\r\n");
    }
    
    
    void web::notifyClients() {
        ws.textAll(String(ledState));
    }

    void web::handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
        AwsFrameInfo *info = (AwsFrameInfo*)arg;
        if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
            data[len] = 0;
            if (strcmp((char*)data, "button_up") == 0) {
                pinMode(KEY800_UP_BUTTON,OUTPUT);
                digitalWrite(KEY800_UP_BUTTON,LOW);
                delay(100);
                pinMode(KEY800_UP_BUTTON,INPUT);
            }
            if (strcmp((char*)data, "button_down") == 0) {
                pinMode(KEY800_DOWN_BUTTON,OUTPUT);
                digitalWrite(KEY800_DOWN_BUTTON,LOW);
                delay(100);
                pinMode(KEY800_DOWN_BUTTON,INPUT);
            }
            if (strcmp((char*)data, "button_menu") == 0) {
                pinMode(KEY800_MENU_BUTTON,OUTPUT);
                digitalWrite(KEY800_MENU_BUTTON,LOW);
                delay(100);
                pinMode(KEY800_MENU_BUTTON,INPUT);
            }
        }
    }
    void web::onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,void *arg, uint8_t *data, size_t len) {
        switch (type) {
            case WS_EVT_CONNECT:
            ESP_LOGI(TAG,"WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
            connected = true;
            break;
            case WS_EVT_DISCONNECT:
            ESP_LOGI(TAG,"WebSocket client #%u disconnected\n", client->id());
            connected = false;
            break;
            case WS_EVT_DATA:
            handleWebSocketMessage(arg, data, len);
            break;
            case WS_EVT_PONG:
            case WS_EVT_ERROR:
            break;
        }
    }

    void web::initWebSocket() {
        ws.onEvent(web_onEvent);
        server.addHandler(&ws);
    }
    String web::processor(const String& var){
        return "X";
    }
    void web::sendwebserial(uint8_t test){
        //if(connected)
            WebSerial.print((String)((char)test));
    }  
    void web::fbuttonsinit(){

        server.on("/fbuttons", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send_P(200, "text/html", fbuttons_html); 
        });

        server.on("/fbuttonsget", HTTP_GET, [] (AsyncWebServerRequest *request) {
            String inputMessage;
            String inputParam;
            // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
            if (request->hasParam(PARAM_INPUT_1)) {
            inputMessage = request->getParam(PARAM_INPUT_1)->value();
            inputParam = PARAM_INPUT_1;
            }
            // GET input2 value on <ESP_IP>/get?input2=<inputMessage>
            else if (request->hasParam(PARAM_INPUT_2)) {
            inputMessage = request->getParam(PARAM_INPUT_2)->value();
            inputParam = PARAM_INPUT_2;
            }
            // GET input3 value on <ESP_IP>/get?input3=<inputMessage>
            else if (request->hasParam(PARAM_INPUT_3)) {
            inputMessage = request->getParam(PARAM_INPUT_3)->value();
            inputParam = PARAM_INPUT_3;
            }
            else {
            inputMessage = "No message sent";
            inputParam = "none";
            }
            Serial.println(inputMessage);
            request->send(200, "text/html", "HTTP GET request sent to your ESP on input field (" 
                                            + inputParam + ") with value: " + inputMessage +
                                            "<br><a href=\"/\">Return to Home Page</a>");
        });
    }
    void web::init(){

        initWebSocket();

        // Route for root / web page
        server.on("/rgbtohdmi", HTTP_GET, [](AsyncWebServerRequest *request){
            request->send_P(200, "text/html", rgbtohdmi);//, processor);
        });

        // Start ElegantOTA
        
        // Start server
        server.begin();
        AsyncElegantOTA.begin(&server);
        WebSerial.begin(&server);
    	WebSerial.msgCallback(WSrecvMsg);
        fbuttonsinit();
        wifiManager.setupConfig();

    }

}
