#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include "BootGif.h"
#include "InteractionGifs.h"
#include "FeedGif.h"
#include "IdleGif.h"
#include "LowLvlGifs.h"
#include "ChargeGif.h"
#include "WidgetGif.h"
#include "AffirmGifs.h"

#define BUTTON1_PIN 12
#define BUTTON2_PIN 13
#define POT_PIN 34
#define MOTOR_PIN 14

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

int hunger = 50;
int happiness = 50;
int boredom = 50;
unsigned long last_lvl_millis = 0;
unsigned long time_to_dec_stat = 10000;
enum State
{
  IDLE,
  FEED,
  PLAY,
  PET_STATUS,
  SETTINGS
};
State currentState = IDLE;

unsigned long lastGifDisplayTime = 0;
const long gifIntervals[] = {30000, 3600000, 10800000, 18000000, 28800000}; // 30min, 1hr, 3hr, 5hr, 8hr

unsigned long lastActivityTime = millis();
const long sleepTimeout = 60000; // 60 seconds of inactivity

const int potThreshold = 50; // Adjust this value based on potentiometer sensitivity
const int NUM_GIFS = 5;      // Number of GIF animations available
const int NUM_Affirm_GIFS = 30;
const int GIF_DISPLAY_TIME = 3000; // GIF display time in milliseconds
const int Vib_Play_Time = 5;

int frame = 0;
int I_frame = 0;
int F_frame = 0;
int Idle_frame = 0;
int LL_frame = 0;
int CA_frame = 0;
int W_frame = 0;
int Af_frame = 0;
#define FRAME_DELAY (42)
#define FRAME_WIDTH (64)
#define FRAME_HEIGHT (64)
#define FRAME_COUNT (sizeof(frames) / sizeof(frames[0]))
#define I_FRAME_COUNT (sizeof(Gif1) / sizeof(Gif1[0]))
#define F_FRAME_COUNT (sizeof(FeedGif) / sizeof(FeedGif[0]))
#define Idle_FRAME_COUNT (sizeof(IdleGif) / sizeof(IdleGif[0]))
#define LL_FRAME_COUNT (sizeof(SadGif) / sizeof(SadGif[0]))
#define CA_FRAME_COUNT (sizeof(ChargeGif) / sizeof(ChargeGif[0]))
#define W_FRAME_COUNT (sizeof(WidgetGif) / sizeof(WidgetGif[0]))
#define Affirm_FRAME_COUNT (sizeof(AffirmGif1) / sizeof(AffirmGif1[0]))

char userName[50]; // Array to store the user's name

int currentPattern = 0; // Current motor vibration pattern index
static int lastPotValue = -1;
int LLG_Flag = 0;

bool isFirstBoot = true; // Variable to remember boot status
bool FTF = true;

int lastButtonState = HIGH;         // the previous state of the button
unsigned long lastDebounceTime = 0; // the last time the button state was toggled
unsigned long debounceDelay = 50;   // the debounce time; increase if the output flickers
unsigned long lastPressTime = 0;    // time of the last button press

// Function prototypes
void setup();
void loop();
bool userIsActive();
void performActiveTasks();
State mapPotToState(int potValue);
void feedPet();
void playWithPet();
void displayRandomGifForDuration(int duration);
void displayHunger();
void FeedPetGif();
void displayPlay();
void showStatus();
void adjustSettings();
void checkGifDisplay();
void goToSleep();
void showBootAnimation();
void displayIdle();
void displayGif(int index);
void displayAffirmGif(int index);
void vibrate_motor();
void saveBootStatus();
void readBootStatus();
void displayGreeting();
void adjustAffirmationInterval();
void adjustVibrationStyle();
void vibrateConstantly();
void vibrateShortBursts();
void vibrateLongBursts();
void vibrateIncreaseIntensity();
void vibrateRandom();
void dispalyLowLvlGifs();
void state_change_check();
void displayChargeAnim();
bool detectButtonPress();
void displayWidgetGif();

void setup()
{
  Serial.begin(115200);
  pinMode(BUTTON1_PIN, INPUT_PULLUP);
  pinMode(BUTTON2_PIN, INPUT_PULLUP);
  pinMode(MOTOR_PIN, OUTPUT);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);

  readBootStatus(); // Read boot status from EEPROM

  if (isFirstBoot)
  {
    showBootAnimation();
    adjustSettings();
    isFirstBoot = false;
    saveBootStatus(); // Save boot status to EEPROM
  }
  else
  {
    displayGreeting();
  }
}

void displayGreeting()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Welcome to");
  display.setCursor(0, 20);
  display.print("Your Pet Pal!");
  display.display();
  delay(2000); // Wait for 2 seconds before proceeding
}

void loop()
{
  if (userIsActive())
  {
    lastActivityTime = millis();
    performActiveTasks();
  }

  if (millis() - lastActivityTime > sleepTimeout)
  {
    goToSleep();
    Serial.println("Test3");
  }
  else
  {
    performActiveTasks();
  }
}

bool userIsActive()
{
  if (FTF)
  {
    lastPotValue = analogRead(POT_PIN);
    FTF = false;
  }
  int currentPotValue = analogRead(POT_PIN);

  // Check if the potentiometer value has changed
  bool potValueChanged = (currentPotValue != lastPotValue);

  // If the potentiometer value has changed, update lastActivityTime
  if (potValueChanged)
  {
    lastActivityTime = millis();
    lastPotValue = currentPotValue; // Update the last potentiometer value
  }

  // Check for button presses
  return digitalRead(BUTTON1_PIN) == LOW ||
         digitalRead(BUTTON2_PIN) == LOW ||
         potValueChanged; // Check if pot value has changed
}

void performActiveTasks()
{
  checkGifDisplay();
  state_change_check();
  if (hunger <= 50 && happiness >= 50 && boredom <= 50)
  {
    displayIdle();
  }
  if (hunger > 50 || happiness < 50 || boredom > 50)
  {
    dispalyLowLvlGifs();
  }
  int selectedOption = 0;   // Default selected option
  bool exitControl = false; // Flag to control exiting settings menu
  unsigned long start_millis = millis();
  while (!exitControl)
  {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Control Menu:");
    display.setCursor(0, 20);
    display.print("1. Charge Animation");
    display.setCursor(0, 30);
    display.print("2. Play Animation");
    display.setCursor(0, 40);
    display.print("3. Show Status");
    display.setCursor(0, 50);
    display.print("4. Settings");

    // Map potentiometer value to select option
    int potValue = analogRead(POT_PIN);
    selectedOption = map(potValue, 0, 4095, 1, 4);

    // Highlight selected option
    display.setCursor(0, selectedOption * 10 + 10);
    display.print("->");

    display.display();

    // Handle button presses
    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      delay(500); // Debounce delay
      switch (selectedOption)
      {
      case 1:
        // Charge Animation selected
        // Implement charge animation
        displayChargeAnim();
        break;
      case 2:
        // Play Animation selected
        // Implement play animation
        playWithPet();
        break;
      case 3:
        // Show Status selected
        // Implement show status
        showStatus();
        break;
      case 4:
        // Settings selected
        // Stay in settings menu
        adjustSettings();
        break;
      }
    }
    // Check if button 2 is pressed to exit settings
    if (digitalRead(BUTTON2_PIN) == LOW)
    {
      delay(500); // Debounce delay
      exitControl = true;
    }
    if ((millis() - start_millis) > 10000)
    {
      break;
    }
  }
}

void state_change_check()
{
  if (millis() - last_lvl_millis > time_to_dec_stat)
  {
    boredom = min(100, boredom + 1);
    happiness = max(0, happiness - 2);
    hunger = min(100, hunger + 3);
    last_lvl_millis = millis();
  }
}

State mapPotToState(int potValue)
{
  int option = map(potValue, 0, 4095, 0, 4);
  return static_cast<State>(option);
}

void feedPet()
{
  hunger = max(0, hunger - 10);
  happiness = min(100, happiness + 5);
  displayHunger();
  FeedPetGif();
}

void displayRandomGifForDuration(int duration)
{
  // Display GIF based on index for specified duration
  int gifIndex = random(1, NUM_GIFS);
  displayGif(gifIndex);
  delay(duration);
}

void displayRandomAffirmationGif(int duration)
{
  // Display GIF based on index for specified duration
  int gifIndex = random(1, NUM_Affirm_GIFS);
  displayAffirmGif(gifIndex);
  delay(duration);
}

void displayHunger()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Hunger level: ");
  display.println(hunger);
  display.display();
  delay(2000); // Display for 2 seconds
}

void playWithPet()
{
  boredom = max(0, boredom - 10);
  happiness = min(100, happiness + 5);
  displayPlay();
  displayRandomGifForDuration(GIF_DISPLAY_TIME);
}

void displayPlay()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Playing with your pet!");
  display.display();
  delay(2000); // Display for 2 seconds
}

void dispalyLowLvlGifs()
{
  LLG_Flag = (LLG_Flag + 1) % 3;
  while (true)
  {
    state_change_check();
    checkGifDisplay();
    if (happiness < 50 && LLG_Flag == 1)
    {
      display.clearDisplay();
      display.drawBitmap(32, 0, SadGif[LL_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      LL_frame = (LL_frame + 1) % LL_FRAME_COUNT;
      delay(FRAME_DELAY);
      if (digitalRead(BUTTON1_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        if (detectButtonPress())
        {
          displayWidgetGif();
          break;
        }
        else
        {
          break;
        }
      }
      if (digitalRead(BUTTON2_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        delay(500);
        break;
      }
    }
    else if (hunger > 50 && LLG_Flag == 2)
    {
      display.clearDisplay();
      display.drawBitmap(32, 0, TiredGif[LL_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      LL_frame = (LL_frame + 1) % LL_FRAME_COUNT;
      delay(FRAME_DELAY);
      if (digitalRead(BUTTON1_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        if (detectButtonPress())
        {
          displayWidgetGif();
          break;
        }
        else
        {
          break;
        }
      }
      if (digitalRead(BUTTON2_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        delay(500);
        break;
      }
    }
    else if (boredom > 50 && LLG_Flag == 0)
    {
      display.clearDisplay();
      display.drawBitmap(32, 0, BoredGif[LL_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      LL_frame = (LL_frame + 1) % LL_FRAME_COUNT;
      delay(FRAME_DELAY);
      if (digitalRead(BUTTON1_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        if (detectButtonPress())
        {
          displayWidgetGif();
          break;
        }
        else
        {
          break;
        }
      }
      if (digitalRead(BUTTON2_PIN) == LOW)
      {
        // currentState = PET_STATUS;
        delay(500);
        break;
      }
    }
  }
}

bool detectButtonPress()
{
  int consecutivePresses = 0;
  unsigned long startTime = millis();

  while (millis() - startTime < 1000)
  {
    int reading = digitalRead(BUTTON1_PIN);
    if (reading != lastButtonState)
    {
      // reset the debounce timer
      lastDebounceTime = millis();
      delay(100);
    }

    if ((millis() - lastDebounceTime) > debounceDelay)
    {
      // if the button state has changed for more than the debounce delay
      if (reading != lastButtonState)
      {
        lastButtonState = reading;

        // if button state changed from high to low (button pressed)
        if (lastButtonState == LOW)
        {
          // if it's the first press or within a short time after the last press, count it
          if (consecutivePresses == 0 || (millis() - lastPressTime) < 500)
          {
            consecutivePresses++;
            Serial.println(consecutivePresses);
            lastPressTime = millis();
          }
          else
          { // otherwise, reset the count
            consecutivePresses = 0;
          }
        }
      }
    }

    // if three consecutive button presses are detected, return true
    if (consecutivePresses == 3)
    {
      return true;
    }
  }

  // if three consecutive button presses are not detected within one second, return false
  return false;
}

void showStatus()
{
  int selectedOption = 0; // Initialize selected option
  bool marked = false;    // Flag to track if an option is marked

  while (true)
  {
    if (!marked)
    {
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Hunger: ");
      display.println(hunger);
      display.setCursor(0, 20);
      display.print("Happiness: ");
      display.println(happiness);
      display.setCursor(0, 40);
      display.print("Boredom: ");
      display.println(boredom);
      display.display();
      delay(3000); // Display for 3 seconds

      marked = true; // Mark the first option
    }
    int potValue = analogRead(POT_PIN);
    selectedOption = map(potValue, 0, 4095, 0, 2);

    switch (selectedOption)
    {
    case 0:
      // Highlight Hunger
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("> Hunger: ");
      display.println(hunger);
      display.setCursor(0, 20);
      display.print("Happiness: ");
      display.println(happiness);
      display.setCursor(0, 40);
      display.print("Boredom: ");
      display.println(boredom);
      display.display();
      break;
    case 1:
      // Highlight Happiness
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Hunger: ");
      display.println(hunger);
      display.setCursor(0, 20);
      display.print("> Happiness: ");
      display.println(happiness);
      display.setCursor(0, 40);
      display.print("Boredom: ");
      display.println(boredom);
      display.display();
      break;
    case 2:
      // Highlight Boredom
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Hunger: ");
      display.println(hunger);
      display.setCursor(0, 20);
      display.print("Happiness: ");
      display.println(happiness);
      display.setCursor(0, 40);
      display.print("> Boredom: ");
      display.println(boredom);
      display.display();
      break;
    }

    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      delay(500); // Debounce delay
      // Perform action based on the selected option
      switch (selectedOption)
      {
      case 0:
        currentState = FEED; // Action for Hunger
        break;
      case 1:
        currentState = PLAY; // Action for Happiness
        break;
      case 2:
        currentState = PLAY; // Action for Boredom
        break;
      }
      // Exit the loop after an option is selected
      break;
    }

    if (digitalRead(BUTTON2_PIN) == LOW)
    {
      delay(500); // Debounce delay
      // Exit the loop if button 2 is pressed
      break;
    }
  }
}

void adjustSettings()
{
  int selectedOption = 1;    // Default selected option
  bool exitSettings = false; // Flag to control exiting settings menu

  while (!exitSettings)
  {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Settings Menu:");
    display.setCursor(0, 20);
    display.print("1. Affir Interval ");
    if (selectedOption == 1)
    {
      display.print("->"); // Indicate the selected option
    }
    display.setCursor(0, 30);
    display.print("2. Vibration Style ");
    if (selectedOption == 2)
    {
      display.print("->"); // Indicate the selected option
    }
    display.display();

    int potValue = analogRead(POT_PIN);
    selectedOption = map(potValue, 0, 4095, 1, 2);

    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      delay(500); // Debounce delay
      switch (selectedOption)
      {
      case 1:
        adjustAffirmationInterval();
        break;
      case 2:
        adjustVibrationStyle();
        break;
      }
    }

    // Check if button 2 is pressed to exit settings
    if (digitalRead(BUTTON2_PIN) == LOW)
    {
      delay(500); // Debounce delay
      exitSettings = true;
    }
  }
}

void adjustAffirmationInterval()
{
  int previousPotValue = -1;
  int intervalIndex = 0; // Default interval index

  while (true)
  {
    int potValue = analogRead(POT_PIN);
    int mappedValue = map(potValue, 0, 4095, 0, 4);

    if (mappedValue != previousPotValue)
    {
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Affirmation Interval:");
      switch (mappedValue)
      {
      case 0:
        display.println("30 min");
        break;
      case 1:
        display.println("1 hr");
        break;
      case 2:
        display.println("3 hrs");
        break;
      case 3:
        display.println("5 hrs");
        break;
      case 4:
        display.println("8 hrs");
        break;
      }
      display.setCursor(0, 20);
      display.print("Press Button 1 to save");
      display.display();
      previousPotValue = mappedValue;
    }

    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      delay(500);  // Debounce delay
      delay(2000); // Display saved message for 2 seconds
      // Save interval setting to EEPROM or any other storage
      break;
    }
  }
}

void adjustVibrationStyle()
{
  bool SC_Flag = false;
  int pre_si = -1;
  // Wait for potentiometer rotation to select style
  while (true)
  {
    int potValue = analogRead(POT_PIN);
    int styleIndex = map(potValue, 0, 4095, 0, 4);
    // Display the selected vibration style
    // For demonstration, let's assume it's a simple text display
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("Vibration Style:");
    // Display available vibration styles here
    // display.display();
    if ((!SC_Flag) && (styleIndex != pre_si))
    {
      SC_Flag = true;
      pre_si = styleIndex;
    }

    display.setCursor(0, 20);
    switch (styleIndex)
    {
    case 0:
      display.print("Style 1");
      display.display();
      if (SC_Flag)
      {
        vibrateConstantly();
        SC_Flag = false;
      }
      break;
    case 1:
      display.print("Style 2");
      display.display();
      if (SC_Flag)
      {
        vibrateShortBursts();
        SC_Flag = false;
      }
      break;
    case 2:
      display.print("Style 3");
      display.display();
      if (SC_Flag)
      {
        vibrateLongBursts();
        SC_Flag = false;
      }
      break;
    case 3:
      display.print("Style 4");
      display.display();
      if (SC_Flag)
      {
        vibrateIncreaseIntensity();
        SC_Flag = false;
      }
      break;
    case 4:
      display.print("Style 5");
      display.display();
      if (SC_Flag)
      {
        vibrateRandom();
        SC_Flag = false;
      }
      break;
    }
    // display.display();

    // Wait for button press to save style setting
    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      delay(500);  // Debounce delay
      delay(2000); // Display saved message for 2 seconds
      // Save style setting to EEPROM or any other storage
      break;
    }
  }
}

void checkGifDisplay()
{
  if (millis() - lastGifDisplayTime >= gifIntervals[currentState])
  {
    vibrate_motor();
    displayRandomAffirmationGif(GIF_DISPLAY_TIME);
    lastGifDisplayTime = millis();
  }
}

void goToSleep()
{
  // Configure wake up sources
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, LOW); // Button 1
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, LOW); // Button 2

  // Enter deep sleep
  esp_deep_sleep_start();
}

void showBootAnimation()
{
  // Implement boot animation
  int i = 0;
  while (i < 10)
  {
    display.clearDisplay();
    display.drawBitmap(32, 0, frames[frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
    display.display();
    frame = (frame + 1) % FRAME_COUNT;
    delay(FRAME_DELAY);
    i++;
  }
}

void displayChargeAnim()
{
  while (true)
  {
    state_change_check();
    display.clearDisplay();
    display.drawBitmap(32, 0, ChargeGif[CA_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
    display.display();
    CA_frame = (CA_frame + 1) % CA_FRAME_COUNT;
    delay(FRAME_DELAY);
    if (digitalRead(BUTTON1_PIN) == LOW || digitalRead(BUTTON2_PIN) == LOW)
    {
      // currentState = PET_STATUS;
      delay(500);
      break;
    }
    // if (hunger > 50 || happiness < 50 || boredom > 50)
    // {
    //   break;
    // }
  }
}

void displayIdle()
{
  // Implement idle state display
  // int i = 0;
  while (true)
  {
    state_change_check();
    checkGifDisplay();
    display.clearDisplay();
    display.drawBitmap(32, 0, IdleGif[Idle_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
    display.display();
    Idle_frame = (Idle_frame + 1) % Idle_FRAME_COUNT;
    delay(FRAME_DELAY);
    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      // currentState = PET_STATUS;
      if (detectButtonPress())
      {
        displayWidgetGif();
        break;
      }
      else
      {
        break;
      }
    }
    if (digitalRead(BUTTON2_PIN) == LOW)
    {
      // currentState = PET_STATUS;
      delay(500);
      break;
    }
    if (hunger > 50 || happiness < 50 || boredom > 50)
    {
      break;
    }
  }
}

void displayWidgetGif()
{
  while (true)
  {
    int potValue = analogRead(POT_PIN);
    int WIF_delay = map(potValue, 0, 4095, 5, 405);
    state_change_check();
    checkGifDisplay();
    display.clearDisplay();
    display.drawBitmap(32, 0, WidgetGif[W_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
    display.display();
    W_frame = (W_frame + 1) % W_FRAME_COUNT;
    delay(WIF_delay);
    if (digitalRead(BUTTON1_PIN) == LOW)
    {
      // currentState = PET_STATUS;
      if (detectButtonPress())
      {
        break;
      }
    }
  }
}

void FeedPetGif()
{
  // Display Feed GIF
  int i = 0;
  while (i < 20)
  {
    display.clearDisplay();
    display.drawBitmap(32, 0, FeedGif[F_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
    display.display();
    F_frame = (F_frame + 1) % F_FRAME_COUNT;
    delay(FRAME_DELAY);
    i++;
  }
}

void displayGif(int index)
{
  // Display GIF based on index
  // Example: display.drawBitmap(...);
  int i = 0;
  while (i < 60)
  {
    switch (index)
    {
    case 1:
      display.clearDisplay();
      display.drawBitmap(32, 0, Gif1[I_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      I_frame = (I_frame + 1) % I_FRAME_COUNT;
      break;
    case 2:
      display.clearDisplay();
      display.drawBitmap(32, 0, Gif2[I_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      I_frame = (I_frame + 1) % I_FRAME_COUNT;
      break;
    case 3:
      display.clearDisplay();
      display.drawBitmap(32, 0, Gif3[I_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      I_frame = (I_frame + 1) % I_FRAME_COUNT;
      break;
    case 4:
      display.clearDisplay();
      display.drawBitmap(32, 0, Gif4[I_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      I_frame = (I_frame + 1) % I_FRAME_COUNT;
      break;
    case 5:
      display.clearDisplay();
      display.drawBitmap(32, 0, Gif5[I_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      I_frame = (I_frame + 1) % I_FRAME_COUNT;
      break;
    }
    delay(FRAME_DELAY);
    i++;
  }
}

void displayAffirmGif(int index)
{
  // Display GIF based on index
  int i = 0;
  while (i < 60)
  {
    switch (index)
    {
    case 1:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif1[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 2:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif2[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 3:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif3[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 4:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif4[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 5:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif5[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 6:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif6[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 7:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif7[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 8:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif8[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 9:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif9[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 10:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif10[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 11:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif11[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 12:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif12[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 13:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif13[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 14:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif14[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 15:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif15[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 16:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif16[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 17:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif17[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 18:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif18[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 19:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif19[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 20:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif20[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 21:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif21[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 22:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif22[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 23:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif23[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 24:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif24[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 25:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif25[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 26:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif26[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 27:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif27[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 28:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif28[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 29:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif29[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    case 30:
      display.clearDisplay();
      display.drawBitmap(32, 0, AffirmGif30[Af_frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
      display.display();
      Af_frame = (Af_frame + 1) % Affirm_FRAME_COUNT;
      break;
    }
    delay(FRAME_DELAY);
    i++;
  }
}

void vibrate_motor()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Pattern: ");
  display.println(currentPattern + 1); // Display the current pattern
  display.display();

  switch (currentPattern)
  {
  case 0:
    vibrateConstantly();
    break;
  case 1:
    vibrateShortBursts();
    break;
  case 2:
    vibrateLongBursts();
    break;
  case 3:
    vibrateIncreaseIntensity();
    break;
  case 4:
    vibrateRandom();
    break;
  }
}

void vibrateConstantly()
{
  digitalWrite(MOTOR_PIN, HIGH);
  delay(1000);
  digitalWrite(MOTOR_PIN, LOW);
  delay(100);
}

void vibrateShortBursts()
{
  for (int i = 0; i < 4; i++)
  {
    digitalWrite(MOTOR_PIN, HIGH);
    delay(100);
    digitalWrite(MOTOR_PIN, LOW);
    delay(300);
  }
}

void vibrateLongBursts()
{
  for (int i = 0; i < 4; i++)
  {
    digitalWrite(MOTOR_PIN, HIGH);
    delay(300);
    digitalWrite(MOTOR_PIN, LOW);
    delay(100);
  }
}

void vibrateIncreaseIntensity()
{
  for (int i = 100; i <= 255; i += 20)
  {
    analogWrite(MOTOR_PIN, i);
    delay(200);
  }
}

void vibrateRandom()
{
  for (int i = 0; i < 10; i++)
  {
    int duration = random(100, 500);
    digitalWrite(MOTOR_PIN, HIGH);
    delay(duration);
    digitalWrite(MOTOR_PIN, LOW);
    delay(random(100, 500));
  }
}

void saveBootStatus()
{
  EEPROM.put(0, isFirstBoot);
  EEPROM.commit();
}

void readBootStatus()
{
  EEPROM.get(0, isFirstBoot);
}