#define CLK_PIN 12  // BTN ENC1
#define DT_PIN 14   // BTN ENC2
#define SW_PIN 13   // BTN ENC

#define DIRECTION_NONE 0   // no change
#define DIRECTION_CCW 1  // counter-clockwise direction
#define DIRECTION_CW 2   // clockwise direction


#define BUTTON_PRESSED_EVENT 1
#define BUTTON_UNPRESSED_EVENT 2
#define BUTTON_NO_CHANGE_EVENT 0


volatile uint8_t rotaryDirection = DIRECTION_NONE;
volatile uint8_t rotaryDirectionPrev = DIRECTION_NONE;
volatile uint32_t rotaryLastTick; 
volatile int rotaryCounter = 0;
volatile int rotaryCounterPrev = 0;
volatile int rotaryCounterPrevDebug = 0;

volatile bool buttonPressed = false;
volatile bool buttonPressedPrev = false;
volatile bool buttonPressedPrevDebug = false;
volatile uint32_t buttonLastTick = 0;

volatile int16_t rotaryPosition = 0;
volatile int16_t rotaryLastPosition = 0;

//volatile int16_t rotaryEncodedPrev = 0;

// Debounce time in milliseconds
const int debounceTime = 2;//2; //default is 2 (best)
volatile unsigned long lastInterruptTimeA = 0;
volatile unsigned long lastInterruptTimeB = 0;
volatile unsigned long lastInterruptTimeButton = 0;
// Variables to keep track of encoder state
volatile int lastEncoded = 0;
volatile long encoderValue = 0;
long lastEncoderValue = 0;

// ISR for encoder A pin
void IRAM_ATTR handleEncoderA() {
  unsigned long currentTime = millis();
  if ((currentTime - lastInterruptTimeA) > debounceTime) {
    int MSB = digitalRead(CLK_PIN);
    int LSB = digitalRead(DT_PIN);
  
    int encoded = (MSB << 1) | LSB;
    int sum = (lastEncoded << 2) | encoded;

    if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011){
      encoderValue--;
      rotaryDirection = DIRECTION_CCW;
    }
    if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000){
      encoderValue++;
      rotaryDirection = DIRECTION_CW;
    }

    lastEncoded = encoded;
    lastInterruptTimeA = currentTime;

    rotaryCounter=encoderValue; //copy to rotaryCounter
    
  }
}

// ISR for encoder B pin
void IRAM_ATTR handleEncoderB() {
  unsigned long currentTime = millis();
  if ((currentTime - lastInterruptTimeB) > debounceTime) {
    handleEncoderA();  // Call handleEncoderA to handle B changes in the same way
    lastInterruptTimeB = currentTime;
  }
}

void InitButtonRotaryHandler(){
  Serial.print("Initializing Button and Rotary Encoder: ");
  buttonPressedPrev = false;
  buttonPressedPrevDebug = false;
  rotaryCounter = 0;
  rotaryCounterPrev = 0;
  rotaryCounterPrevDebug = 0;
  rotaryDirection = DIRECTION_NONE;
  rotaryDirectionPrev = DIRECTION_NONE;
  rotaryLastTick = millis();
  buttonLastTick = millis();
  pinMode(DT_PIN, INPUT_PULLUP);
  pinMode(CLK_PIN, INPUT_PULLUP);
  pinMode(SW_PIN, INPUT_PULLUP);
  // button.setDebounceTime(5);
  attachInterrupt(digitalPinToInterrupt(CLK_PIN), handleEncoderA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(DT_PIN), handleEncoderB, CHANGE);

  // Initialize button pin
  //pinMode(SW_PIN, INPUT_PULLUP); // Assuming the button is active low
  //attachInterrupt(digitalPinToInterrupt(SW_PIN), ButtonInterrupt, CHANGE);

  Serial.println("OK");
}

bool ButtonIsPressed(){
  if (millis() - buttonLastTick < 10 ) return buttonPressed; //debounce
  buttonPressed = digitalRead(SW_PIN) == LOW;
  buttonLastTick = millis();
  return buttonPressed;
}

//return 0 = no change, 1 = pressed, 2 = unpressed
uint8_t ButtonSwitchedEvent(){
  //Serial.println("A");
  if (millis() - buttonLastTick < 10 ) return BUTTON_NO_CHANGE_EVENT; //debounce
  //Serial.println("B");
  buttonPressed = digitalRead(SW_PIN) == LOW;
  buttonLastTick = millis();
  if (buttonPressed!=buttonPressedPrev){
    buttonPressedPrev = buttonPressed;
    if (buttonPressed) return BUTTON_PRESSED_EVENT;
    return BUTTON_UNPRESSED_EVENT;
  }else{
    return BUTTON_NO_CHANGE_EVENT; //no change
  }
}

//Reset Button flag for event
void ButtonResetEvent(){
  buttonPressed = digitalRead(SW_PIN) == LOW;
  buttonPressedPrev = buttonPressed;
  buttonLastTick = millis();
}

//Reset Rotary flag for event
void RotaryResetEvent(){
  rotaryCounter = 0;
  rotaryCounterPrev = 0;
  encoderValue = 0;
  rotaryDirection = DIRECTION_NONE;
  rotaryDirectionPrev = DIRECTION_NONE;
}

//Get rotary last direction then clear flag
uint8_t RotaryEvent(){
  if (rotaryDirection!=DIRECTION_NONE) lastInterruptTimeB = millis(); //debounce it again from last consume
  uint8_t v = rotaryDirection;
  rotaryDirection = DIRECTION_NONE;
  rotaryDirectionPrev = DIRECTION_NONE;
  return v;
}

//for debug testing
void ButtonRotaryDebugRoutine(){
  if (buttonPressedPrevDebug!=buttonPressed){
    buttonPressedPrevDebug = buttonPressed;
    Serial.print("Button: ");
    Serial.println((buttonPressed?"1":"0"));
  }

  if (rotaryCounter!=rotaryCounterPrevDebug){
    rotaryCounterPrevDebug = rotaryCounter;
    if (rotaryDirection!=DIRECTION_NONE){
      Serial.print("Rotary: ");
      Serial.print((rotaryDirection==DIRECTION_CW?">":"<"));
      Serial.print(" (");
      Serial.print(rotaryCounterPrevDebug);
      Serial.println(")");
    }
  }
  
}
