#pragma once

#include <Arduino.h>

#include <ArduinoJson.h>

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#include <SimpleSerialProtocol.h>

#include <StateData.h>

namespace Connection {
    const char* ssid = "Dragonvale";
    const char* password = "Dr4g0nSl4yr";
    const int jsonBufferSize = 1024;

    // Serial Device
    SimpleSerialProtocol controller;

    // Wifi WebServer
    ESP8266WebServer server(80);

    // Serial
    void initSerial();
    void handleSerial();
    void onControllerPacket(Packet packet);

    // Wifi
    void initWifi();
    void handleWifi();
    void sendResponse(DynamicJsonDocument response);

    void onApiStatusRoute();
    void getCurrentStateRoute();
    void onDeviceRoute();
}

// serial
void Connection::initSerial(){
    controller.init(0, 115200);
    controller.sendPacket("controller", "serial_status", "ready");
}

void Connection::handleSerial(){
    controller.receivePackets(onControllerPacket);
}

void Connection::onControllerPacket(Packet packet) {

    if(strcmp(packet.id, "access") == 0) {
        if (strcmp(packet.command, "update_state") == 0) {
            StateData::updateState(packet.data);
        }
    }
}

// wifi
void Connection::initWifi(){
    controller.sendPacket("controller", "wifi_status", "init_connecting");

    // Set wifi config
    WiFi.hostname("KrabbyHome");
    WiFi.begin(ssid, password);

    // check connection status
    while (WiFi.status() != WL_CONNECTED) {
        controller.sendPacket("controller", "wifi_status", "connecting");
        delay(500);
    }

    // send status
    controller.sendPacket("controller", "wifi_status", "connected");
    
    // Send details
    char ipAdress[50];
    WiFi.localIP().toString().toCharArray(ipAdress,50);
    controller.sendPacket("controller", "wifi_details", ipAdress);

    server.on("/api/status", Connection::onApiStatusRoute);
    server.on("/api/currentstate", Connection::getCurrentStateRoute);
    server.on("/api/device", Connection::onDeviceRoute);

    server.begin();
}

void Connection::handleWifi() {
    server.handleClient();
}

void Connection::sendResponse(DynamicJsonDocument response) {
    // Prepare data to return
    char serializedJson[jsonBufferSize];
    serializeJson(response, serializedJson);

    //added cors
    server.sendHeader("Access-Control-Allow-Origin", "*");
    // Send response
    server.send(200, "application/json", serializedJson);
}

void Connection::onApiStatusRoute() {
    // Init Json Document
    DynamicJsonDocument response(jsonBufferSize);

    // Insert data
    response["status"] = "success";
    response["health"] = "healthy";
    response["uptime"] = millis();

    // Send response
    sendResponse(response);
}

void Connection::getCurrentStateRoute() {
    // Init Json Document
    DynamicJsonDocument response(jsonBufferSize);

    // Insert data
    response["status"] = "success";
    response["state"] = StateData::state;


    // Send response
    sendResponse(response);
}

void Connection::onDeviceRoute() {
    // Init Json Document
    DynamicJsonDocument response(jsonBufferSize);

    // Check params 
    if (server.arg("id").isEmpty() || server.arg("action").isEmpty() || server.arg("data").isEmpty()) {
        response["status"] = "error";
        response["msg"] = "Invalid parameter fields!";
        return sendResponse(response);   
    }

    // Get parameters from request
    int idBuffer = server.arg("id").length() + 1;
    char id[idBuffer];
    server.arg("id").toCharArray(id, idBuffer);
    
    int commandBuffer = server.arg("action").length() + 1;
    char command[commandBuffer];
    server.arg("action").toCharArray(command, commandBuffer);

    int dataBuffer = server.arg("data").length() + 1;
    char data[dataBuffer];
    server.arg("data").toCharArray(data, dataBuffer);
    
    // Send packet to controller
    controller.sendPacket(id, command, data);

    response["status"] = "success";
    response["msg"] = "Processed command!";
    
    sendResponse(response); 
}