#include "pinDevice.h"
#include "interface.h"
#include "system_t.h"
#include "menuDisplay.h"

#include "ThingsBoard.h"
#include <WiFi.h>   
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define WIFI_AP_NAME              "Wokwi-GUEST"
#define WIFI_PASSWORD             ""
#define THINGSBOARD_SERVER        "thingsboard.cloud"
#define THINGSBOARD_ACCESSTOKEN   "tAVNMYa06xMP1bSzVcV9"
WiFiClient espClient;
ThingsBoard tb(espClient);
int status = WL_IDLE_STATUS;

bool subscribed = false;
void InitWiFi() {
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network
  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

RPC_Response processDelayChange(const RPC_Data &data)
{
  Serial.println("Received the set delay RPC method");
}

RPC_Response processGetDelay(const RPC_Data &data)
{
  Serial.println("Received the get value method");
//  return String(led_delay);
}
RPC_Response processSetGpioState(const RPC_Data &data)
{
  Serial.println("Received the set GPIO RPC method");
}

RPC_Response processGetGpioState(const RPC_Data &data) {
  Serial.println("Received the get GPIO RPC method");
}
// RPC handlers
RPC_Callback callbacks[] = {
  { "setValue",         processDelayChange },
  { "getValue",         processGetDelay },  
  { "setGpioStatus",    processSetGpioState },
  { "getGpioStatus",    processGetGpioState },
};


TaskHandle_t btnTask;
TaskHandle_t timeTask;
TaskHandle_t interfaceTask;

void setupRTOS(void)
{
  xTaskCreatePinnedToCore(task_button,"Task_button",1024,NULL,2,&btnTask,0); 
  xTaskCreatePinnedToCore(task_time,"Task_tm",2048,NULL,1,&timeTask,1);
  xTaskCreatePinnedToCore(task_interface,"Task_interface",4096,NULL,1,&interfaceTask,0); 
}


void setup() {
  // put your setup code here, to run once:
  pinMode(indicator_pin, OUTPUT);
  digitalWrite(indicator_pin,HIGH);
  delay(1000);
  digitalWrite(indicator_pin,LOW);

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();


  Serial.begin(115200);
  Serial.println("Initializing system");
  interface::display::setup();
  setupRTOS();
}

void loop() {
  vTaskDelay(1000);
}

void task_interface(void *pvParameters)
{
  while(1)
  {
    interface::display::loop();
    vTaskDelay(100);
  }
}

void defaultAnyButtonPressed(void)
{
    digitalWrite(indicator_pin,HIGH);
}

void task_button(void *pvParameters)
{
  interface::button_setup();
  interface::attachAnyPressed(defaultAnyButtonPressed);
  // vTaskDelay(1000);
  while(1)
  {
      interface::button_loop();
      vTaskDelay(10);
  }
}

void task_time(void *pvParameters)
{
  device_system::setup();
  uint32_t time_ = millis();
  uint8_t hasSpread = 0;
  uint8_t lastSpread = 0;
  uint8_t hour_, minute_;
  time_schedule buff;
  uint32_t timeUpdateIOT = 0;
  bool servoStat=false;
  while(1)
  {
    if( interface::isButtonLongPressed(buttonOK) )
      hasSpread = 1;
      
    if(millis() - time_ >=750)
    {
      device_system::sensor_loop();
      interface::display::setLevel(device_system::getTankPercent());
      time_ = millis();
    }
    hour_ = device_system::getHours();
    minute_ = device_system::getMinutes();
    for(uint8_t i=0; i<3; i++)
    {
      hasSpread = 0;
      buff=interface::display::getSchedule(i);
      if( buff.hours == hour_ && buff.minutes==minute_)
      {
        hasSpread = 1;
        break;
      };
    };
    if( hasSpread != lastSpread && hasSpread==1){
      servoStat = true;
      device_system::openValve();
      vTaskDelay((interface::display::getType()+1)*250);
      device_system::closeValve();
      device_system::spreadOn(interface::display::getRange());
    }else{
      servoStat = false;
      device_system::spreadOff();
    }
    lastSpread = hasSpread;

    if( device_system::getTankPercent() < 20 )// in percent
    {
      uint8_t t_ = map((uint8_t)device_system::getTankPercent(),0,20,5,0);
      device_system::buzzerPulse(t_, 1);
    }else
      device_system::buzzerPulse(0, 0);



    // IOT-function

    // Reconnect to WiFi, if needed
    if (WiFi.status() != WL_CONNECTED) {
      reconnect();
    }else{
      // Reconnect to ThingsBoard, if needed
      if (!tb.connected()) {
        subscribed = false;

        // Connect to the ThingsBoard
        Serial.print("Connecting to: ");
        Serial.print(THINGSBOARD_SERVER);
        Serial.print(" with token ");
        Serial.println(THINGSBOARD_ACCESSTOKEN);
        if (!tb.connect(THINGSBOARD_SERVER, THINGSBOARD_ACCESSTOKEN)) {
          Serial.println("Failed to connect");
        }
      }else   // connect to server
      {
        // Subscribe for RPC, if needed
        if (!subscribed) {
          Serial.println("Subscribing for RPC... ");

          // Perform a subscription. All consequent data processing will happen in
          // callbacks as denoted by callbacks[] array.
          if (!tb.RPC_Subscribe(callbacks, COUNT_OF(callbacks))) {
            Serial.println("Failed to subscribe for RPC");
          }
          Serial.println("Subscribe done");
          subscribed = true;
        }  

        // need more check 
        if( subscribed )
        {
            if( millis() - timeUpdateIOT >= 5000 )
            {
                tb.sendTelemetryFloat("Sisa Pakan", device_system::getTankPercent());
                tb.sendTelemetryFloat("Status Servo", servoStat);
                timeUpdateIOT = millis();
            }
        }

      }
    }




    vTaskDelay(100);
  }
}