// --- Программа для Arduino: Живые глаза с режимом сна (Версия 6.0 - Сонное засыпание) ---
// --- 1. Анимация засыпания теперь многоступенчатая и более естественная.
// --- 2. Добавлена универсальная функция для анимации высоты глаз.

#include <GyverOLED.h>

GyverOLED<SSD1306_128x64, OLED_BUFFER> oled;

// Глобальные константы
const int eyeWidth = 40;
const int fullEyeHeight = 25;
const int eyeSpacing = 8;
const int EYE_SHIFT_AMOUNT = 5;
const int EYE_LOOK_PAUSE = 600;
const int BLINK_ANIM_DELAY = 0.5;
const int MOVE_ANIM_DELAY = 0.5;
const int BLINK_STEP = 5;
const long AWAKE_DURATION = 30000;
const long SLEEP_DURATION = 15000;
const int ZZZ_FRAME_DELAY = 200;
const int Z_BOX_X = 100, Z_BOX_Y = 0, Z_BOX_W = 27, Z_BOX_H = 20;

// Глобальные переменные
int leftEye_x0, leftEye_x1, rightEye_x0, rightEye_x1;
int eyeCenterY;
int currentEyeShift = 0;
unsigned long stateChangeTime = 0;
unsigned long lastActionTime = 0;
long nextActionDelay = 3000;
#define STATE_AWAKE 0
#define STATE_ASLEEP 1
int programState = STATE_AWAKE;
unsigned long lastZzzFrameTime = 0;
int zzzScale = 1;

void setup() {
  oled.init();
  
  int totalWidth = (eyeWidth * 2) + eyeSpacing;
  int startX = (128 - totalWidth) / 2;
  int startY = (64 - fullEyeHeight) / 2;
  leftEye_x0 = startX;
  leftEye_x1 = startX + eyeWidth;
  rightEye_x0 = leftEye_x1 + eyeSpacing;
  rightEye_x1 = rightEye_x0 + eyeWidth;
  eyeCenterY = startY + (fullEyeHeight / 2);

  delay(500);
  animateOpening();
  delay(300);
  performLookAroundAnimation();
  
  stateChangeTime = millis();
  lastActionTime = millis();
}

// Базовые функции
void drawEyes(int currentHeight, int shift) {
  if (currentHeight < 2) currentHeight = 2;
  int y0 = eyeCenterY - (currentHeight / 2);
  int y1 = eyeCenterY + (currentHeight / 2);
  oled.roundRect(leftEye_x0 + shift, y0, leftEye_x1 + shift, y1, OLED_FILL);
  oled.roundRect(rightEye_x0 + shift, y0, rightEye_x1 + shift, y1, OLED_FILL);
}

void animateEyeShift(int targetShift) {
  int step = (targetShift > currentEyeShift) ? 1 : -1;
  for (int shift = currentEyeShift; shift != targetShift; shift += step) {
    oled.clear(); drawEyes(fullEyeHeight, shift); oled.update(); delay(MOVE_ANIM_DELAY);
  }
  currentEyeShift = targetShift;
  oled.clear(); drawEyes(fullEyeHeight, currentEyeShift); oled.update();
}

// --- НОВАЯ универсальная функция для анимации высоты глаз ---
void animateEyeHeight(int startHeight, int endHeight) {
  // Определяем направление анимации: закрытие (отрицательный шаг) или открытие (положительный)
  int step = (startHeight > endHeight) ? -BLINK_STEP : BLINK_STEP;

  // Цикл, который работает для обоих направлений
  for (int h = startHeight; (step > 0) ? (h <= endHeight) : (h >= endHeight); h += step) {
    oled.clear();
    drawEyes(h, 0); // Анимация высоты происходит только в центральном положении
    oled.update();
    delay(BLINK_ANIM_DELAY);
  }
  // Убедимся, что в конце глаза имеют точную конечную высоту
  oled.clear();
  drawEyes(endHeight, 0);
  oled.update();
}

// Старые функции теперь просто вызывают новую, универсальную
void animateClosing() {
  animateEyeHeight(fullEyeHeight, 0);
}

void animateOpening() {
  animateEyeHeight(0, fullEyeHeight);
}

void drawZgraphic(int x, int y, int width, int height) {
  oled.line(x, y, x + width, y);
  oled.line(x + width, y, x, y + height);
  oled.line(x, y + height, x + width, y + height);
}

void drawSleepFrame(int scale) {
  oled.clear();
  int z_width = 3 * scale;
  int z_height = 5 * scale;
  int currentX = Z_BOX_X + (Z_BOX_W - z_width) / 2;
  int currentY = Z_BOX_Y + (Z_BOX_H - z_height) / 2;
  drawZgraphic(currentX, currentY, z_width, z_height);
  drawEyes(0, 0);
  oled.update();
}

// Функции высокого уровня
void performBlinkAnimation() {
  animateClosing(); delay(25); animateOpening();
}

void performLookAroundAnimation() {
  if (random(2) == 0) {
    animateEyeShift(-EYE_SHIFT_AMOUNT); delay(EYE_LOOK_PAUSE);
    animateEyeShift(EYE_SHIFT_AMOUNT);  delay(EYE_LOOK_PAUSE);
  } else {
    animateEyeShift(EYE_SHIFT_AMOUNT);   delay(EYE_LOOK_PAUSE);
    animateEyeShift(-EYE_SHIFT_AMOUNT); delay(EYE_LOOK_PAUSE);
  }
  animateEyeShift(0);
}

// --- ОБНОВЛЕННАЯ, многоступенчатая функция засыпания ---
void performFallAsleepSequence() {
  // Определяем пороговые высоты для "сонных" глаз
  int sleepyHeight1 = fullEyeHeight * 0.7; // ~70% открыты
  int sleepyHeight2 = fullEyeHeight * 0.4; // ~40% открыты

  // Этап 1: Глаза немного прикрываются
  animateEyeHeight(fullEyeHeight, sleepyHeight1);
  delay(600); // Пауза, "борьба со сном"

  // Этап 2: Глаза прикрываются еще сильнее
  animateEyeHeight(sleepyHeight1, sleepyHeight2);
  delay(800); // Более длинная пауза, почти заснул

  // Этап 3: Глаза полностью закрываются
  animateEyeHeight(sleepyHeight2, 0);
}

void performWakeUpSequence() {
  animateOpening();
  delay(300);
  performLookAroundAnimation();
}


// Функция loop() (без изменений)
void loop() {
  unsigned long currentTime = millis();
  if (programState == STATE_AWAKE) {
    if (currentTime - stateChangeTime >= AWAKE_DURATION) {
      performFallAsleepSequence();
      programState = STATE_ASLEEP;
      stateChangeTime = currentTime;
      lastZzzFrameTime = currentTime;
      zzzScale = 1;
      return;
    }
    if (currentTime - lastActionTime >= nextActionDelay) {
      if (random(4) == 0) {
        performLookAroundAnimation();
      } else {
        performBlinkAnimation();
      }
      lastActionTime = currentTime;
      nextActionDelay = random(5000, 15000);
    }
  } else if (programState == STATE_ASLEEP) {
    if (currentTime - stateChangeTime >= SLEEP_DURATION) {
      performWakeUpSequence();
      programState = STATE_AWAKE;
      stateChangeTime = currentTime;
      lastActionTime = currentTime;
      return;
    }
    if (currentTime - lastZzzFrameTime >= ZZZ_FRAME_DELAY) {
      int next_z_width = 3 * (zzzScale + 1);
      int next_z_height = 5 * (zzzScale + 1);
      drawSleepFrame(zzzScale); 
      if (next_z_width > Z_BOX_W || next_z_height > Z_BOX_H) {
        zzzScale = 1;
      } else {
        zzzScale++;
      }
      lastZzzFrameTime = currentTime;
    }
  }
}