//author: pavan kalsariya
//project: Cake the best desktop compaion robot
//microcontroller: ESP32
//THIS FIE CONTAINS CODE FOR 2.4' OLED



#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>
#include <FluxGarage_RoboEyes.h>

// OLED Configuration
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_MOSI 23
#define OLED_CLK 18
#define OLED_DC 2
#define OLED_CS 5
#define OLED_RESET 4

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

// NeoPixel Configuration
#define LED_PIN 27
#define LED_COUNT 4
Adafruit_NeoPixel leds(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

// RoboEyes Instance
roboEyes eyes;

// Enumeration for Expressions
enum EyeExpression {
  EXPR_NORMAL,
  EXPR_CURIOUS,
  EXPR_ANGRY
};

// Function Declarations
void showText(const char* text, uint8_t size, uint16_t duration);
void bootLEDSequence();
void blinkEyes();
void setExpression(EyeExpression expr);
void curiousLEDAnimation();
void angryLEDAnimation();

void setup() {
  Serial.begin(115200);

  // Initialize Display
  if (!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.clearDisplay();
  display.display();

  // Initialize LEDs
  leds.begin();
  leds.setBrightness(100);
  leds.clear();
  leds.show();

  // Initialize RoboEyes
  eyes.begin(SCREEN_WIDTH, SCREEN_HEIGHT, 100);
  eyes.close();

  // Sequence Start
  showText("Hiii I am,", 2, 2000);
  showText("CAKE", 3, 2000);
  eyes.close();
  delay(1000);
  setExpression(EXPR_NORMAL);
  delay(2000);
  blinkEyes();
  setExpression(EXPR_CURIOUS);
  curiousLEDAnimation();
  delay(3000);
  setExpression(EXPR_ANGRY);
  angryLEDAnimation();
}

void loop() {
  // Main loop left empty as the sequence is handled in setup()
}

void showText(const char* text, uint8_t size, uint16_t duration) {
  display.clearDisplay();
  display.setTextSize(size);
  display.setTextColor(SSD1306_WHITE);
  int16_t x = (SCREEN_WIDTH - strlen(text) * 6 * size) / 2;
  int16_t y = (SCREEN_HEIGHT - 8 * size) / 2;
  display.setCursor(x, y);
  display.print(text);
  display.display();
  delay(duration);
}

void bootLEDSequence() {
  for (int i = 0; i < LED_COUNT; i++) {
    leds.setPixelColor(i, leds.Color(0, 0, 255));
    leds.show();
    delay(200);
  }
  for (int i = 0; i < 3; i++) {
    leds.fill(leds.Color(255, 255, 255));
    leds.show();
    delay(100);
    leds.clear();
    leds.show();
    delay(100);
  }
}

void blinkEyes() {
  eyes.close();
  delay(200);
  eyes.open();
  delay(200);
}

void setExpression(EyeExpression expr) {
  eyes.setAutoblinker(OFF);
  eyes.setIdleMode(OFF);
  eyes.setHFlicker(OFF);
  eyes.setVFlicker(OFF);

  switch (expr) {
    case EXPR_NORMAL:
      eyes.setMood(DEFAULT);
      eyes.setAutoblinker(ON, 4, 2);
      eyes.setIdleMode(ON, 5, 3);
      break;
    case EXPR_CURIOUS:
      eyes.setMood(CURIOUS);
      eyes.setIdleMode(ON, 2, 1);
      break;
    case EXPR_ANGRY:
      eyes.setMood(ANGRY);
      eyes.setHFlicker(ON, 3);
      break;
  }
}

void curiousLEDAnimation() {
  for (int i = 0; i < 30; i++) {
    float pulse = 0.5 + 0.5 * sin(millis() / 500.0);
    uint32_t color = leds.Color(50, 150 * pulse, 100);
    for (int j = 0; j < LED_COUNT; j++) {
      leds.setPixelColor(j, color);
    }
    leds.show();
    delay(100);
  }
}

void angryLEDAnimation() {
  for (int i = 0; i < 50; i++) {
    float intensity = 0.5 + 0.5 * sin(millis() / 200.0);
    uint32_t color = leds.Color(200 * intensity, 0, 0);
    for (int j = 0; j < LED_COUNT; j++) {
      leds.setPixelColor(j, color);
    }
    leds.show();
    delay(100);
  }
}
