#include <Adafruit_NeoPixel.h>

#define LED_PIN     D0  
#define BUTTON_PIN  D2   
#define VIB_PIN     D1   
#define NUM_LEDS    8
#define BRIGHTNESS  5


Adafruit_NeoPixel ring(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

// Device state
bool deviceOn = false;
int mode = 0;

// Button handling
unsigned long pressStart = 0;
unsigned long lastPressTime = 0;
bool lastButtonState = HIGH;
bool longPressHandled = false;

const unsigned long longPressTime = 1000;
const unsigned long doublePressGap = 400;

// Panic mode
bool panicMode = false;
unsigned long panicStart = 0;
const unsigned long panicDuration = 60000;

// Breathing engine
unsigned long phaseStart = 0;
int phase = 0;
float breathProgress = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(VIB_PIN, OUTPUT);

  ring.begin();
  ring.setBrightness(BRIGHTNESS);
  ring.clear();
  ring.show();
}

void loop() {
  handleButton();

  if (deviceOn) {
    updateBreathing();
  }
}

// ================= BUTTON =================
void handleButton() {
  bool currentState = digitalRead(BUTTON_PIN);

  // Button pressed
  if (currentState == LOW && lastButtonState == HIGH) {
    pressStart = millis();
    longPressHandled = false;
  }

  // Long press
  if (currentState == LOW && !longPressHandled) {
    if (millis() - pressStart > longPressTime) {
      deviceOn = !deviceOn;
      longPressHandled = true;

      if (!deviceOn) {
        turnOffAll();
      } else {
        resetBreathing();
      }
    }
  }

  // Button released
  if (currentState == HIGH && lastButtonState == LOW) {

    if (!longPressHandled && deviceOn) {

      unsigned long now = millis();

      // Double press → Panic mode
      if (now - lastPressTime < doublePressGap) {
        panicMode = true;
        panicStart = now;
        resetBreathing();
      }
      else {
        mode++;
        if (mode > 1) mode = 0;
        resetBreathing();
      }

      lastPressTime = now;
    }
  }

  lastButtonState = currentState;
}

// ================= BREATHING =================
void updateBreathing() {

  if (panicMode) {
    runPanicMode();
    if (millis() - panicStart > panicDuration) {
      panicMode = false;
      resetBreathing();
    }
    return;
  }

  unsigned long now = millis();

  int inhaleTime = 4000;
  int holdTime   = 4000;
  int exhaleTime = (mode == 0) ? 6000 : 4000;
  int restTime   = 1500;

  int phaseDuration;

  switch (phase) {

    case 0: // INHALE
      phaseDuration = inhaleTime;
      breathProgress = (float)(now - phaseStart) / phaseDuration;
      if (breathProgress >= 1.0) {
        phase = 1;
        phaseStart = now;
      }
      applyFrame(getColor(), constrain(breathProgress,0,1));
      break;

    case 1: // HOLD
      phaseDuration = holdTime;
      if (now - phaseStart >= phaseDuration) {
        phase = 2;
        phaseStart = now;
      }
      applyFrame(getColor(), 1.0);
      break;

    case 2: // EXHALE
      phaseDuration = exhaleTime;
      breathProgress = 1.0 - ((float)(now - phaseStart) / phaseDuration);
      if (breathProgress <= 0.0) {
        phase = 3;
        phaseStart = now;
      }
      applyFrame(getColor(), constrain(breathProgress,0,1));
      break;

    case 3: // REST
      phaseDuration = restTime;
      if (now - phaseStart >= phaseDuration) {
        phase = 0;
        phaseStart = now;
      }
      applyFrame(getColor(), 0.05);
      break;
  }
}

// ================= PANIC MODE =================
void runPanicMode() {

  unsigned long now = millis();

  int inhaleTime = 3000;
  int holdTime   = 3000;
  int exhaleTime = 4000;

  int phaseDuration;

  switch (phase) {

    case 0:
      phaseDuration = inhaleTime;
      breathProgress = (float)(now - phaseStart) / phaseDuration;
      if (breathProgress >= 1.0) {
        phase = 1;
        phaseStart = now;
      }
      applyPanicFrame(constrain(breathProgress,0,1));
      break;

    case 1:
      phaseDuration = holdTime;
      if (now - phaseStart >= phaseDuration) {
        phase = 2;
        phaseStart = now;
      }
      applyPanicFrame(1.0);
      break;

    case 2:
      phaseDuration = exhaleTime;
      breathProgress = 1.0 - ((float)(now - phaseStart) / phaseDuration);
      if (breathProgress <= 0.0) {
        phase = 0;
        phaseStart = now;
      }
      applyPanicFrame(constrain(breathProgress,0,1));
      break;
  }
}

// ================= LED + VIBRATION =================
void applyFrame(uint32_t color, float factor) {

  uint8_t r = ((color >> 16) & 0xFF) * factor;
  uint8_t g = ((color >> 8) & 0xFF) * factor;
  uint8_t b = (color & 0xFF) * factor;

  for (int i = 0; i < NUM_LEDS; i++) {
    ring.setPixelColor(i, r, g, b);
  }
  ring.show();

  int vibStrength = factor * 255;
  analogWrite(VIB_PIN, vibStrength);
}

void applyPanicFrame(float factor) {

  uint8_t r = 255 * factor;
  uint8_t g = 80 * factor;
  uint8_t b = 0;

  for (int i = 0; i < NUM_LEDS; i++) {
    ring.setPixelColor(i, r, g, b);
  }
  ring.show();

  int vibStrength = 100 + (factor * 155);
  analogWrite(VIB_PIN, vibStrength);
}

// ================= HELPERS =================
uint32_t getColor() {
  if (mode == 0) return ring.Color(0, 0, 255);   // 4-4-6 Blue
  else return ring.Color(0, 255, 120);           // 4-4-4 Teal
}

void resetBreathing() {
  phase = 0;
  phaseStart = millis();
}

void turnOffAll() {
  ring.clear();
  ring.show();
  analogWrite(VIB_PIN, 0);
}