#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h>

// ---------------- LCD + Keypad ----------------
LiquidCrystal_I2C lcd(0x27, 20, 4);  // Change 0x27 to 0x3F if blank

const byte ROWS = 4;
const byte COLS = 4;
int Number = 0;
float Zstep = 1;
float XYstep = 10;
int Feedrate = 1000;

// ---------------- SD Card ----------------
#define SD_CS 10    // Chip Select pin for SD card module
File gcodeFile;

char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

// ---------------- Setup ----------------
void setup() {
  Serial.begin(115200);

  lcd.init();
  lcd.begin(20, 4);   // force 20x4 mode
  lcd.backlight();

  lcd.setCursor(0, 0);
  lcd.print("XY Step =  ");
  lcd.print(XYstep);
  lcd.setCursor(0, 1);
  lcd.print("Z Step =  ");
  lcd.print(Zstep);
  lcd.setCursor(0, 2);
  lcd.print("Feedrate =  ");
  lcd.print(Feedrate);

  // --- Initialize SD card ---
  if (!SD.begin(SD_CS)) {
    lcd.setCursor(0, 3);
    lcd.print("SD init failed   ");
  } else {
    lcd.setCursor(0, 3);
    lcd.print("SD Ready         ");
  }
}

// ---------------- Send G-code File ----------------
void sendFileToGRBL(const char *filename) {
  gcodeFile = SD.open(filename);
  if (!gcodeFile) {
    lcd.setCursor(0, 3);
    lcd.print("File open error  ");
    return;
  }

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Running:");
  lcd.setCursor(0, 1);
  lcd.print(filename);

  while (gcodeFile.available()) {
    String line = gcodeFile.readStringUntil('\n');
    line.trim();
    if (line.length() > 0) {
      Serial.println(line);   // Send G-code to GRBL
      delay(20);              // Allow GRBL buffer to catch up
    }
  }

  gcodeFile.close();
  lcd.setCursor(0, 3);
  lcd.print("Done Running     ");
}

// ---------------- Main Loop ----------------
void loop() {
  char customKey = customKeypad.getKey();
  if (customKey) {
    Number = customKey - '0';

    // ---------------- Motion Commands ----------------
    if (Number == 1) { Serial.print("$J=G91 Z"); Serial.print(Zstep); Serial.print("F"); Serial.println(Feedrate); }
    if (Number == 2) { Serial.print("$J=G91 Y"); Serial.print(XYstep); Serial.print("F"); Serial.println(Feedrate); }
    if (Number == 4) { Serial.print("$J=G91 X"); Serial.print(-XYstep); Serial.print("F"); Serial.println(Feedrate); }
    if (Number == 6) { Serial.print("$J=G91 X"); Serial.print(XYstep); Serial.print("F"); Serial.println(Feedrate); }
    if (Number == 8) { Serial.print("$J=G91 Y"); Serial.print(-XYstep); Serial.print("F"); Serial.println(Feedrate); }
    if (Number == 7) { Serial.print("$J=G91 Z"); Serial.print(-Zstep); Serial.print("F"); Serial.println(Feedrate); }

    // ---------------- Step/Feedrate Adjustments ----------------
    if (Number == 17) { XYstep = XYstep * 10; }
    if (Number == 18) { XYstep = XYstep / 10; }
    if (Number == 19) { Zstep = Zstep * 10; }
    if (Number == 20) { Zstep = Zstep / 10; }
    if (Number == 0)  { XYstep = XYstep - 1; }
    if (Number == 5)  { XYstep = XYstep + 1; }
    if (Number == 3)  { Feedrate = Feedrate * 10; }
    if (Number == 9)  { Feedrate = Feedrate / 10; }

    // ---------------- LCD Refresh ----------------
    lcd.setCursor(0, 0);
    lcd.print("XY Step =  ");
    lcd.print(XYstep);
    lcd.print("   "); // clear trailing

    lcd.setCursor(0, 1);
    lcd.print("Z Step =  ");
    lcd.print(Zstep);
    lcd.print("   ");

    lcd.setCursor(0, 2);
    lcd.print("Feedrate =  ");
    lcd.print(Feedrate);
    lcd.print("   ");

    // ---------------- SD Card Functions ----------------
    if (customKey == 'A') {
      // Run specific file
      sendFileToGRBL("test.gcode");
    }
    if (customKey == 'B') {
      // List files (first 3)
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Files:");
      File root = SD.open("/");
      int line = 1;
      while (true) {
        File entry = root.openNextFile();
        if (!entry) break;
        if (!entry.isDirectory()) {
          lcd.setCursor(0, line);
          lcd.print(entry.name());
          line++;
        }
        entry.close();
        if (line > 3) break; // show max 3 files
      }
      root.close();
    }
  }
}
