#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
#include "alarm.h"
// #include <Dictionary.h>
#include "Dict.h"
#include "Times.h"




// https://randomnerdtutorials.com/esp32-mfrc522-rfid-reader-arduino/
MFRC522DriverPinSimple ss_pin(5);
class CardReader{
private:
  String user1="0438768a2c6a80";
  String user2="23141f2d";

  MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
  //MFRC522DriverI2C driver{};     // Create I2C driver
  MFRC522 mfrc522{driver};         // Create MFRC522 instance
  AlarmStatus* status;
  long lastCardRead =1;
  bool doubleReaded=false;
  bool initialized=false;
  bool failed=false;
  long restartAttempt=0;
  long lastRestart=0;

  Dictionary &users = *(new Dictionary());

  using PCD_Version = MFRC522Constants::PCD_Version;
  using StatusCode = MFRC522Constants::StatusCode;
public:
  CardReader(AlarmStatus* statusRef)
  {
    status = statusRef;
  }

  void Init(){
    initialized = mfrc522.PCD_Init();
    if(!initialized) return;
    Serial.print("Card Reader init: ");
    MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial);	// Show details of PCD - MFRC522 Card Reader details.
    lastRestart=millis();
    lastCardRead=millis();
  }

  void AddUser(String id, String name){
    users(id, name);
  }

  bool IsInit(){
    return initialized;
  }

  void HandleCard(){
    if(!initialized){
      return;
    }
    if(failed && restartAttempt + FromSeconds(2) < millis()){
      restartAttempt=millis();
      mfrc522.PCD_Reset();
      auto version = mfrc522.PCD_GetVersion();
      if(version == PCD_Version::Version_Unknown) {
        Serial.println("restart attempt unsuccessful");
        return;
      }
      Serial.print("Card reader: Restart attempt ok: ");
      MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial);
      failed=false;
      mfrc522.PCD_Init();
      
      return;
    }

    if(failed){
      return;
    }

    if(lastRestart + FromMinutes(5) < millis()){
      lastRestart =millis();
      mfrc522.PCD_Reset();
      if(!mfrc522.PCD_Init()){
        failed = true;
        restartAttempt=millis();
        Serial.print("Card reader - Restart failure");
        return;
      }
      // Serial.print("Card reader -  Restart ok: ");
      MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial);
      return;
    }

    if (!mfrc522.PICC_IsNewCardPresent()) {
      return;
    }

    if(lastCardRead + FromSeconds(1) > millis())
    {
      doubleReaded=true;
      return;
    }
    lastCardRead = millis();

    // Select one of the cards.
    if (!mfrc522.PICC_ReadCardSerial()) {
      
      auto sc = mfrc522.PICC_HaltA();
      if(sc == StatusCode::STATUS_ERROR){
        Serial.println("Connection with card reader failed");
        failed=true;
        restartAttempt=millis();
      }else{
        Serial.println("Card Reader: Could not read");
      }
      
      status->showError =true;
      return;
    }

    // Dump debug info about the card; PICC_HaltA() is automatically called.
    // MFRC522Debug::PICC_DumpToSerial(mfrc522, Serial, &(mfrc522.uid));

    // Serial.print("Card UID: ");
    // MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
    // Serial.println();

    // Save the UID on a String variable
    String uidString = "";
    for (byte i = 0; i < mfrc522.uid.size; i++) {
      if (mfrc522.uid.uidByte[i] < 0x10) {
        uidString += "0"; 
      }
      uidString += String(mfrc522.uid.uidByte[i], HEX);
    }
    Serial.print("Card Read: ");Serial.println(uidString);

    for (int i = 0; i < users.count(); i++) {
      if(users(i) == uidString){
        status->allowed=true;
        status->userAllowed=users[i];
        return;
      }
    }

    Serial.println("access not granted");
    status->showError =true;
  }
};
