#include <Arduino.h>
// #include "DictionaryDeclarations.h"
#include <Dictionary.h>
#include "alarm.h"
#include "DoorSensor.h"
#include "LedController.h"
#include "Siren.h"
#include "CardReader.h"
#include "soc/rtc_wdt.h"
#include <WiFi.h>
#include "ServerConnector.h"
// #include <WiFiClientSecure.h>
// #include "FrancelsoftCert.h"

#include "Times.h"
// #include <Dictionary.h>

AlarmStatus s;
DoorSensor doorSensor(&s);
LedController led(&s);
Siren siren(&s);
CardReader cardReader(&s);
ServerConnector serverConnector(&s, &cardReader);

const int SILENCE_JMP_PIN = 12;
//const char*  server = "push.francelsoft.com";  // Server URL



void printStatus()
{
  String msg = String("Door: ") + String(doorSensor.IsDoorOpen() ? "Open" : "Closed");
  msg = msg + " | Alarm: " + String(s.isArmed ? "Armed" : "Disarmed");
  msg = msg + " | Is Fired: " + String(s.isFired ? "Fired" : "Not Fired");
  msg = msg + " | Led: " + String(s.ledOn ? "On" : "Off");
  msg = msg + " | Silent: " + String(s.silent ? "Silent" : "Loud");
  msg = msg + " | Muted: " + String(s.muted ? "Muted" : "Not Muted");
  Serial.println(msg);
}

void setup()
{
  Serial.begin(115200);

  doorSensor.Init();
  led.Init();
  siren.Init();
  cardReader.Init();

  pinMode(SILENCE_JMP_PIN, INPUT_PULLUP);

  s.silent = false;
  s.isArmed = doorSensor.IsDoorClosed();

  addUsers();

  // WiFi.mode(WIFI_STA);
  // WiFi.disconnect();
  // delay(100);
  SoundAlarmAsync();
  // StartNotifierAsync();

  printStatus();

  ConnectToWifi();

  // setClock();
  serverConnector.StartNotifierAsync();
}

void addUsers(){
  cardReader.AddUser("0438768a2c6a80", "pin verizure");
  // cardReader.AddUser("23141f2d", "pin azul");
  cardReader.AddUser("91cf3e02", "card access");
}

void loop()
{
  //Inputs
  s.silent = digitalRead(SILENCE_JMP_PIN) == LOW;

  doorSensor.HandleDoor();

  if(cardReader.IsInit()){
    cardReader.HandleCard();
  }else{
    cardReader.Init();
  }

  if(s.allowed){
    HandleUserPresent();
    s.allowed=false;
  }

  if (s.doorChanged)
  {
    DoorEvent();
    s.doorChanged = false;
  }

  AutoRearm();

  //Output
  if(s.showError){
    led.Error();
    s.showError=false;
  }
  led.Update();

  // delay(1000);
}

void DoorEvent()
{
  if (doorSensor.IsDoorOpen())
  {
    Serial.println("The door-opening");
    
    if (!s.isArmed)
    {
      Serial.println("Alarm is dissarmed, not fireing");
      return;
    }
    if(s.isFired){ // Already fired.
      return;
    }
    Serial.println("Alarm is armed, firing");
    s.isFired = true;
    s.sendNotif=true;
  }
  else
  {
    // delay(500);
    Serial.println("The door-closing");
    s.isArmed = true;
  }
}

void HandleUserPresent(){
  Serial.print("User Allowed: ");
  Serial.println(s.userAllowed);
  s.lastEntrance=millis();
  if(s.isFired){
    s.isFired=false;
    s.isArmed=s.doorStatus==DOOR_CLOSED;
  }else{
    s.isArmed=false;
  }
}

void AutoRearm(){
  if(s.isArmed){
    return;
  }
  if(s.lastEntrance + FromMinutes(3) < millis()){

    //Auto Rearm if door is closed.
    if(s.doorStatus == DOOR_CLOSED){
      Serial.println("5m Passed, AutoArming again");
      s.isArmed= true;
    }

    //Autofire if door open when expired
    // if(s.doorStatus == DOOR_OPEN){
    //   s.isFired=true;
    //   return;
    // }
  }
}

TaskHandle_t SoundTask;
void SoundAlarmAsync(){
  xTaskCreate(SoundAlarmIntAsync, "task1", 1000, NULL, 1, NULL);
}

void SoundAlarmIntAsync( void * pvParameters ){
  for(;;){
      if (!s.isFired)
      {
        vTaskDelay( 200 / portTICK_PERIOD_MS );
        continue;
      }
      siren.SoundSiren();
      vTaskDelay( 1 / portTICK_PERIOD_MS );
  }
}


void ConnectToWifi(){
  // We start by connecting to a WiFi network
    WiFi.begin("Guile&Andre", "popolitoproducciones");

    Serial.println();
    Serial.println();
    Serial.print("Waiting for WiFi... ");

    while(WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
}


void setClock() {
  // configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
}