#include <IRremote.h>
#include <LowPower.h>

#define _WOKWI_
#define _DEBUG_

#define Boton_Off 0xA2 //0x5DA2FF00
#define Boton_0 0x68 //0x9768FF00
#define Boton_1 0x30 //0xCF30FF00
#define Boton_2 0x18 //0xE718FF00


/*
  #define Boton_Off 0xE31CFF00  // cambia los códigos por los de tu control
  #define Boton_0   0xE619FF00
  #define Boton_1   0xBA45FF00
  #define Boton_2   0xB946FF00
*/
const byte SENSOR = 2;
const byte LED = 9;

const unsigned long FADEDELAY = 5;  // tiempo entre cambio de valor de brillo
unsigned long newTime, oldTime;  // para el efecto del led

bool pwrOff = false;  // Inicio, false = normal, true = powerdown
bool pwrState = pwrOff;

#ifdef _WOKWI_
volatile bool simularPowerDown = false;  // para simular powerDown en wokwi
#endif

int brillo = 0;

IRrecv irrecv(SENSOR);
decode_results codigo;

void IR_ISR() {  // INT0
  detachInterrupt(digitalPinToInterrupt(SENSOR));
#ifdef _WOKWI_
  simularPowerDown = false;  // para simular powerDown en wokwi
#endif
}

void manejar_led() {
  newTime = millis();
  if (newTime - oldTime >= FADEDELAY ) {  // delay entre saltos de brillo
    oldTime = newTime;
    if (!pwrOff && brillo < 255) {  // encendiendo led
      brillo++;
      analogWrite(LED, brillo);
    }
    else if (pwrOff && brillo > 0) {  // apagando led
      brillo--;
      analogWrite(LED, brillo);
    }
  }
}

void setup() {
#ifdef _DEBUG_
  Serial.begin(115200);
#endif
  pinMode(SENSOR, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pwrOff == false);
  irrecv.enableIRIn();

  oldTime = millis();  // para el parpadeo de muestra
}

void loop() {

  if (irrecv.decode()) {
#ifdef _DEBUG_
//    Serial.println(irrecv.decodedIRData.decodedRawData, HEX);
    Serial.println(irrecv.decodedIRData.command, HEX);
#endif
    switch (irrecv.decodedIRData.command){ //decodedRawData) {
      case Boton_0:
      case Boton_1:
      case Boton_2:
        pwrOff = false;
        pwrState = false;
        break;
      case Boton_Off:
        pwrOff = true;
        pwrState = true;
        break;
      default:
        pwrOff = pwrState;
#ifdef _DEBUG_
        Serial.print("Tecla no valida. ");
        Serial.println(pwrOff ? "Vuelve a dormir." : "");
#endif
    }
    irrecv.resume();
  }

  manejar_led();

  if (pwrOff && brillo == 0 ) {
    delay(200);  // para evitar detección de nuevos pulsos del C/R
    digitalWrite(LED_BUILTIN, LOW);
#ifdef _DEBUG_
    Serial.println("PowerDown");
#endif
    noInterrupts();
    EIFR = bit(INTF0);  // limpia interrupciones que pudiesen quedar pendientes
    attachInterrupt(digitalPinToInterrupt(SENSOR), IR_ISR, FALLING);
    interrupts();

#ifdef _WOKWI_
// --- Simula powerDown en wokwi ---
    simularPowerDown = true;
    while (simularPowerDown);
// ---------------------------------
#else
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);  // *** A dormir! ***
#endif

    digitalWrite(LED_BUILTIN, HIGH);
    pwrOff = false;
#ifdef _DEBUG_
    Serial.println("Wakeup!");
#endif
  }
//  irrecv.resume();
  delay(1);
}