#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Initialize the LCD: address 0x27, 16 characters, 2 lines
LiquidCrystal_I2C lcd(0x27, 16, 2); // Adjust the I2C address if needed

// Define pins for joystick module
const int vryPin = A0;    // Y-axis
const int vrxPin = A1;    // X-axis
const int buttonPin = 2;  // Button

// Device list
const int listSize = 15;
const String devices[listSize] = {
  "DEVICE 1",
  "DEVICE 2",
  "DEVICE 3",
  "DEVICE 4",
  "DEVICE 5",
  "DEVICE 6",
  "DEVICE 7",
  "DEVICE 8",
  "DEVICE 9",
  "DEVICE 10",
  "DEVICE 11",
  "DEVICE 12",
  "DEVICE 13",
  "DEVICE 14",
  "DEVICE 15"
};

// Enumeration for screen states
enum ScreenState { LIST_SCREEN, CONNECTING_SCREEN };
ScreenState currentScreen = LIST_SCREEN;

// Current index for list display
int currentIndex = 0;

// Variables to store readings and joystick state
int yValue = 0;
int xValue = 0;
String mainDirection = "Center";
bool isCentered = true;

// Timing variables for holding in a single direction
unsigned long holdStartTime = 0;
const unsigned long holdIncrementInterval = 500; // 500 milliseconds

// Variables for button handling
bool lastButtonState = HIGH; // Assume button is not pressed initially
bool buttonPressed = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50; // 50 milliseconds debounce

// Variable to store selected device
String selectedDevice = "";

// Function prototypes
void displayMessage();
void displaySearchingMessage();
void displayDeviceFound();
void displayList(const String list[], int listSize, int currentIndex);
void showConnectingScreen();
void showListScreen();

void setup() {
  // Initialize Serial for debugging (optional)
  Serial.begin(115200); // Initialize Serial for debugging (if needed)
  
  // Initialize the LCD
  lcd.init();
  lcd.backlight();

  // Set button pin as input with pull-up resistor
  pinMode(buttonPin, INPUT_PULLUP);

  // Display initial messages
  displayMessage();           // Display "ECOROOTS" and scrolling message
  displaySearchingMessage(); // Display "SEARCHING ENVIRONMENT FOR DEVICES" and scrolling message
  displayDeviceFound();      // Display "1 DEVICE FOUND"

  // After initial messages, display the device list
  showListScreen();
}

void loop() {
  // Read the current button state
  int reading = digitalRead(buttonPin);

  // Check for button state change (debounce)
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // If the button state has changed
    if (reading != buttonPressed) {
      buttonPressed = reading;

      // If the button is pressed (assuming LOW when pressed)
      if (buttonPressed == LOW) {
        if (currentScreen == LIST_SCREEN) {
          // Save the first line device
          selectedDevice = devices[currentIndex];
          // Switch to CONNECTING_SCREEN
          currentScreen = CONNECTING_SCREEN;
          showConnectingScreen();
        }
        // You can add functionality for button press on CONNECTING_SCREEN if needed
      }
    }
  }

  lastButtonState = reading; // Save the current reading for next loop

  // Read analog values from Y and X axes
  yValue = analogRead(vryPin);
  xValue = analogRead(vrxPin);

  // Determine Y-axis direction
  String yDirection = "";
  if (yValue > 800) { // Adjusted threshold
    yDirection = "Up";
  } else if (yValue < 200) { // Adjusted threshold
    yDirection = "Down";
  } else {
    yDirection = "Center";
  }

  // Determine X-axis direction
  String xDirection = "";
  if (xValue > 800) { // Adjusted threshold
    xDirection = "Right";
  } else if (xValue < 200) { // Adjusted threshold
    xDirection = "Left";
  } else {
    xDirection = "Center";
  }

  // Determine current direction based on Y and X directions
  String currentDirection = "Center";
  if (yDirection != "Center") {
    currentDirection = yDirection;
  } else if (xDirection != "Center") {
    currentDirection = xDirection;
  }

  // Handle actions based on the current screen
  if (currentScreen == LIST_SCREEN) {
    // Handle joystick navigation for list screen
    if (currentDirection == "Center") {
      isCentered = true;
      mainDirection = "Center";
      holdStartTime = 0; // Reset the hold time when joystick is centered
    }
    else if (isCentered) {
      // Update main direction if joystick was previously centered
      mainDirection = currentDirection;
      isCentered = false;
      
      // Handle the main direction
      if (mainDirection == "Up") {
        if (currentIndex > 0){
          currentIndex--;
          displayList(devices, listSize, currentIndex);
        }
      }
      else if (mainDirection == "Down") {
        if (currentIndex < listSize - 2){
          currentIndex++;
          displayList(devices, listSize, currentIndex);
        }
      }
      // Left and Right directions can be handled if needed
      
      // Start hold timer
      holdStartTime = millis();
    }
    else if (mainDirection == currentDirection && holdStartTime > 0) {
      // Check if 500 milliseconds have passed since the last increment
      if (millis() - holdStartTime >= holdIncrementInterval) {
        // Handle the main direction
        if (mainDirection == "Up") {
          if (currentIndex > 0){
            currentIndex--;
            displayList(devices, listSize, currentIndex);
          }
        }
        else if (mainDirection == "Down") {
          if (currentIndex < listSize - 2){
            currentIndex++;
            displayList(devices, listSize, currentIndex);
          }
        }
        // Reset hold timer to count every 500 milliseconds
        holdStartTime = millis();
      }
    }
  }
  else if (currentScreen == CONNECTING_SCREEN) {
    // In CONNECTING_SCREEN, check if joystick is moved left to return to LIST_SCREEN
    if (currentDirection == "Left") {
      currentScreen = LIST_SCREEN;
      showListScreen();
    }
    // You can add other interactions for CONNECTING_SCREEN if needed
  }

  // Add a small delay to stabilize readings
  delay(75);
}

// Function to display the initial "ECOROOTS" message
void displayMessage() {
  lcd.clear();

  // Display "ECOROOTS" centered on the first row
  lcd.setCursor((16 - 8) / 2, 0); // (16 - 8)/2 centers "ECOROOTS" (8 chars) on a 16-char display
  lcd.print("ECOROOTS");

  String message = "ROOTING SUSTAINABILITY INTO THE FUTURE";

  int scrollLength = message.length() - 16;

  if (scrollLength <= 0) {
    // Message fits on screen, no scrolling needed
    lcd.setCursor((16 - message.length()) / 2, 1);
    lcd.print(message);
    delay(5000);
  } else {
    int totalScrollSteps = scrollLength + 1; // To account for full scrolling
    int delayTime = 5000 / totalScrollSteps; // Time per scroll step

    for (int pos = 0; pos <= scrollLength; pos++) {
      lcd.setCursor(0, 1);
      lcd.print(message.substring(pos, pos + 16));
      delay(delayTime);
    }
  }
}

// Function to display the "SEARCHING ENVIRONMENT FOR DEVICES" message
void displaySearchingMessage() {
  lcd.clear();

  String message = "SEARCHING ENVIRONMENT FOR DEVICES";

  int scrollLength = message.length() - 16;

  if (scrollLength <= 0) {
    // Message fits on screen, no scrolling needed
    lcd.setCursor((16 - message.length()) / 2, 0);
    lcd.print(message);
    delay(5000);
  } else {
    int totalScrollSteps = scrollLength + 1; // To account for full scrolling
    int delayTime = 5000 / totalScrollSteps; // Time per scroll step

    for (int pos = 0; pos <= scrollLength; pos++) {
      lcd.setCursor(0, 0);
      lcd.print(message.substring(pos, pos + 16));
      delay(delayTime);
    }
  }
}

// Function to display "1 DEVICE FOUND"
void displayDeviceFound() {
  lcd.clear();
  // Display "1 DEVICE FOUND" centered on the first row
  lcd.setCursor((16 - 13) / 2, 0); // 13 characters for "1 DEVICE FOUND"
  lcd.print("1 DEVICE FOUND");
  delay(1000); // Display it for 1 second
}

// Function to display the list of devices based on currentIndex (Left-Aligned)
void displayList(const String list[], int listSize, int currentIndex) {
  lcd.clear();

  // Display first item on the first line (left-aligned)
  String firstItem = list[currentIndex];
  if (firstItem.length() > 16) {
    firstItem = firstItem.substring(0, 16); // Truncate if longer than 16 chars
  }
  lcd.setCursor(0, 0);
  lcd.print(firstItem);

  // Display second item on the second line (left-aligned)
  if (currentIndex + 1 < listSize) {
    String secondItem = list[currentIndex + 1];
    if (secondItem.length() > 16) {
      secondItem = secondItem.substring(0, 16); // Truncate if longer than 16 chars
    }
    lcd.setCursor(0, 1);
    lcd.print(secondItem);
  } else {
    lcd.setCursor(0, 1);
    lcd.print(" "); // Clear second line if no item
  }
}

// Function to show the connecting screen
void showConnectingScreen() {
  lcd.clear();
  
  // Display "CONNECTING TO" on the first line
  String connectingMsg = "CONNECTING TO";
  lcd.setCursor(0, 0);
  lcd.print(connectingMsg);

  // Display "{DEVICE SELECTED}" on the second line, left-aligned
  String deviceMsg = selectedDevice;
  if (deviceMsg.length() > 16) {
    deviceMsg = deviceMsg.substring(0, 16); // Truncate if longer than 16 chars
  }
  lcd.setCursor(0, 1);
  lcd.print(deviceMsg);
  
  // Optionally, you can add more functionality here, such as attempting to connect
}

// Function to show the list screen
void showListScreen() {
  displayList(devices, listSize, currentIndex);
}

in tha bove text create a funciton that checks every line displayed on the LCD Screen if its length is greater than 16 charecters, and then scrolls it from left to right every two seconds as long as the screen isnt changed