#include <Keypad.h>
#include <TM1637Display.h>
#define CLK1 22 
#define DIO1 23 
#define CLK2 21 
#define DIO2 19 
#define ROTARY_PIN1 26 
#define ROTARY_PIN2 27 
#define ROTARY_BUTTON 25 
#define DEBOUNCE_DELAY 200
#define RESET_DEBOUNCE_DELAY 100
TM1637Display display1(CLK1, DIO1);
TM1637Display display2(CLK2, DIO2);
const byte ROWS = 4; 
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {16, 17, 18, 0}; 
byte colPins[COLS] = {2, 4, 5, 15}; 
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
int lastEncoded = 0;
unsigned long lastDebounceTime = 0;
int availableScores[] = {101, 180, 301, 501, 701, 901};
int playerScores[2] = {0, 0};
int scoreIndex = 3;
bool scoreLocked = false;
int currentPlayer = 1;
String currentInput = "";
int previousScores[3] = {0, 0, 0}; // Array per memorizzare gli ultimi tre punteggi
int previousPlayers[3] = {0, 0, 0}; // Array per memorizzare i giocatori associati ai punteggi
int scoreIndexHistory = 0; // Indice per tenere traccia della posizione corrente nell'array
int lastPlayer = 0; 
void handleRotaryEncoder() {
  if (scoreLocked) return;
  int MSB = digitalRead(ROTARY_PIN1);
  int LSB = digitalRead(ROTARY_PIN2);
  int currentEncoded = (MSB << 1) | LSB;
  int sum = (lastEncoded << 2) | currentEncoded;
  unsigned long currentTime = millis();
  if (currentTime - lastDebounceTime > DEBOUNCE_DELAY) {
    if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) {
      scoreIndex = min(scoreIndex + 1, (int)(sizeof(availableScores) / sizeof(availableScores[0]) - 1));
      display1.showNumberDec(availableScores[scoreIndex], false);
      lastDebounceTime = currentTime;
    } else if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) {
      scoreIndex = max(scoreIndex - 1, 0);
      display1.showNumberDec(availableScores[scoreIndex], false);
      lastDebounceTime = currentTime;
    }
  }
  lastEncoded = currentEncoded;
}
void handleButtonPress() {
  bool buttonState = digitalRead(ROTARY_BUTTON) == LOW;
  if (buttonState && !scoreLocked && millis() - lastDebounceTime > DEBOUNCE_DELAY) {
    scoreLocked = true;
    playerScores[0] = availableScores[scoreIndex];
    playerScores[1] = availableScores[scoreIndex];
    currentPlayer = 1;
    updateDisplays();
    lastDebounceTime = millis();
  }
}
void handleKeypad() {
  if (!scoreLocked) return;
  char key = customKeypad.getKey();
  if (key) {
    if (key == 'A') {  
      scoreIndex = 3;
      scoreLocked = false;
      display1.showNumberDec(availableScores[scoreIndex], false);
      display2.clear();
    } else if (key == 'B') {  
      for (int i = 0; i < 3; i++) {
        if (previousPlayers[i] != 0) {
          playerScores[previousPlayers[i] - 1] += previousScores[i];
        }
      }
      updateDisplays();
    } else if (key == '#') {
      if (currentInput.length() > 0) {
        int score = currentInput.toInt();
        previousScores[scoreIndexHistory % 3] = score; // Memorizza il punteggio nell'array
        previousPlayers[scoreIndexHistory % 3] = currentPlayer; // Memorizza il giocatore nell'array
        scoreIndexHistory++;
        playerScores[currentPlayer - 1] -= score;
        currentInput = "";
        currentPlayer = currentPlayer % 2 + 1; 
        updateDisplays();
      }
    } else if (isdigit(key)) {
      currentInput += key;
      displayCurrentInput();
    }
  }
}
uint8_t* getDigitSegments(int num) {
    static uint8_t segData[4];
    for (int i = 0; i < 4; i++) {
        segData[i] = 0;
    }
    int digitPos = 3;
    do {
        segData[digitPos--] = display1.encodeDigit(num % 10);
        num /= 10;
    } while (num > 0 && digitPos >= 0);
    return segData;
}
void updateDisplays() {
    uint8_t segPlayer1[4] = {0x00, 0x00, 0x00, 0x00};
    uint8_t segPlayer2[4] = {0x00, 0x00, 0x00, 0x00};
    memcpy(segPlayer1, getDigitSegments(playerScores[0]), 4);
    memcpy(segPlayer2, getDigitSegments(playerScores[1]), 4);
    if (currentPlayer == 1) {
        segPlayer1[0] |= 0x40; 
    } else {
        segPlayer2[0] |= 0x40; 
    }
    display1.setSegments(segPlayer1);
    display2.setSegments(segPlayer2);
}
void displayCurrentInput() {
    uint8_t segData[4] = {0x00, 0x00, 0x00, 0x00};
    memcpy(segData, getDigitSegments(currentInput.toInt()), 4);
    if (currentPlayer == 1) {
        display1.setSegments(segData);
    } else {
        display2.setSegments(segData);
    }
}
void setup() {
  Serial.begin(9600);
  pinMode(ROTARY_PIN1, INPUT_PULLUP);
  pinMode(ROTARY_PIN2, INPUT_PULLUP);
  pinMode(ROTARY_BUTTON, INPUT_PULLUP);
  display1.setBrightness(0x0f);
  display2.setBrightness(0x0f);
  display1.showNumberDec(availableScores[scoreIndex], false);
  display2.clear();
}
void loop() {
  if (!scoreLocked) {
    handleRotaryEncoder();
  }
  handleButtonPress();
  handleKeypad();
}