#include <SPI.h>
#include <EEPROM.h>
#include "font.h" // Your font.h file with alphabets[][5] and FONT_LENGTH

#define BUTTON_MODE 4
#define BUTTON_UP   5
#define BUTTON_DOWN 6

unsigned long previousMillis = 0;
int hours = 12;
int minutes = 0;
int seconds = 0;

int settingMode = 0; // 0 = normal, 1 = set hours, 2 = set minutes, 3 = set seconds

byte bitmap[8][9]; // 7x60 display (8 rows, 9 zones)
int numZones = sizeof(bitmap[0]);
int maxZoneIndex = numZones - 1;
int numCols = numZones * 8;

void setup() {
  SPI.begin();
  Serial.begin(9600);

  pinMode(BUTTON_MODE, INPUT_PULLUP);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);

  pinMode(2, OUTPUT); // clockPin
  pinMode(3, OUTPUT); // dataPin
  pinMode(7, OUTPUT); // latchPin
  pinMode(10, OUTPUT); // ssPin

  clearBitmap();
}

void loop() {
  updateTime();
  handleButtons();
  clearBitmap();
  displayTime();
  RefreshDisplay();
}

void updateTime() {
  static unsigned long lastUpdate = 0;
  unsigned long currentMillis = millis();
  if (currentMillis - lastUpdate >= 1000 && settingMode == 0) {
    lastUpdate = currentMillis;
    seconds++;
    if (seconds >= 60) {
      seconds = 0;
      minutes++;
      if (minutes >= 60) {
        minutes = 0;
        hours++;
        if (hours >= 24) hours = 0;
      }
    }
  }
}

void handleButtons() {
  static unsigned long lastDebounce = 0;
  if (millis() - lastDebounce < 200) return;
  lastDebounce = millis();

  if (digitalRead(BUTTON_MODE) == LOW) {
    settingMode++;
    if (settingMode > 3) settingMode = 0;
  }

  if (digitalRead(BUTTON_UP) == LOW) {
    if (settingMode == 1) hours = (hours + 1) % 24;
    if (settingMode == 2) minutes = (minutes + 1) % 60;
    if (settingMode == 3) seconds = (seconds + 1) % 60;
  }

  if (digitalRead(BUTTON_DOWN) == LOW) {
    if (settingMode == 1) hours = (hours + 23) % 24;
    if (settingMode == 2) minutes = (minutes + 59) % 60;
    if (settingMode == 3) seconds = (seconds + 59) % 60;
  }
}

void displayTime() {
  char timeStr[9];
  sprintf(timeStr, "%02d:%02d:%02d", hours, minutes, seconds);

  bool blinkOn = (millis() % 1000) < 500;

  // Flashing logic: replace digits with spaces if blink is off
  if (settingMode == 1 && !blinkOn) {
    timeStr[0] = ' ';
    timeStr[1] = ' ';
  }
  if (settingMode == 2 && !blinkOn) {
    timeStr[3] = ' ';
    timeStr[4] = ' ';
  }
  if (settingMode == 3 && !blinkOn) {
    timeStr[6] = ' ';
    timeStr[7] = ' ';
  }

  renderText(timeStr);
}

void renderText(const char* text) {
  int colOffset = 18;
  for (int i = 0; text[i] != '\0'; i++) {
    int index = text[i] - ' ';
    if (index < 0 || index >= FONT_LENGTH) index = 0;

    for (int col = 0; col < 5; col++) {
      if (colOffset >= numCols) return;
      byte column = alphabets[index][col];
      for (int row = 0; row < 7; row++) {
        bool isOn = bitRead(column, row);
        Plot(colOffset, row + 1, isOn);
      }
      colOffset++;
    }
    colOffset++; // spacing
  }
}

void clearBitmap() {
  for (int row = 0; row < 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0;
    }
  }
}

void Plot(int col, int row, bool isOn) {
  int zone = col / 8;
  int flippedZone = maxZoneIndex - zone; // Flip zone index
  int colBitIndex = 7 - (col % 8);       // Flip column bit index
  byte colBit = 1 << colBitIndex;

  if (isOn)
    bitmap[row][flippedZone] |= colBit;
  else
    bitmap[row][flippedZone] &= ~colBit;
}

void RefreshDisplay() {
  for (int row = 0; row < 8; row++) {
    int rowbit = 1 << row;
    PORTD &= ~(1 << PD7); // latch low
    delay(1);
    shiftOut(3, 2, MSBFIRST, rowbit ^ 0xFF); // dataPin, clockPin
    PORTD |= (1 << PD7); // latch high

    SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
    PORTB |= (1 << PB2); // ssPin high

    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      SPI.transfer(bitmap[row][zone]);
    }

    PORTB &= ~(1 << PB2); // ssPin low
    SPI.endTransaction();
    delayMicroseconds(300);
  }
}