// Neopixel Color Picker
// 11/2/2025

// Turn pot to change color or brightness
// Press button to toggle between color and brightness
// Read HSV or RGB value in Serial Monitor

#include <FastLED.h>
#define LED_PIN 2
#define NUM_LEDS 1
#define BUTTON_PIN 4
#define POT_PIN A0
CRGB leds[NUM_LEDS];
bool modeColor = true;  // true = color mode, false = brightness mode
int buttonState;        // current stable state
int lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
uint8_t hue = 0;
float brightness = 0.5;

// For change detection (reduce serial spam)
static uint8_t lastHue = 255;
static float lastBrightness = -1.0;

// Smooth potentiometer reading
int readPotSmooth() {
  int sum = 0;
  for (int i = 0; i < 5; i++) {
    sum += analogRead(POT_PIN);
    delay(2);
  }
  return sum / 5;
}

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  analogReference(DEFAULT);
  FastLED.setBrightness(brightness * 255);
  leds[0] = CHSV(hue, 255, 255);
  FastLED.show();
  Serial.println(F("Arduino Color Picker Example"));
  Serial.println(F("Press button to toggle between color and brightness control"));
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);
  // --- Debounce the button ---
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      // Toggle on press (HIGH → LOW)
      if (buttonState == LOW) {
        modeColor = !modeColor;
        Serial.println();
        Serial.println(F("--------------------------"));
        Serial.print(F("Mode changed to: "));
        Serial.println(modeColor ? F("COLOR") : F("BRIGHTNESS"));
        Serial.println(F("--------------------------"));
        // --- Visual indicator flash ---
        if (modeColor) {
          // Flash current hue at *full* brightness for visibility
          FastLED.setBrightness(255);
          leds[0] = CHSV(hue, 255, 255);
        } else {
          // Flash white at current brightness
          FastLED.setBrightness(brightness * 255);
          leds[0] = CRGB::White;
        }
        FastLED.show();
        delay(500);  // flash duration
        // Restore last display
        FastLED.setBrightness(brightness * 255);
        leds[0] = CHSV(hue, 255, 255);
        FastLED.show();
        delay(500);  // pause so user can notice the change
      }
    }
  }
  lastButtonState = reading;

  // --- Potentiometer reading (smoothed) ---
  int potValue = readPotSmooth();

  if (modeColor) {
    // Map pot to hue range 0–230 (avoid red wraparound)
    hue = map(potValue, 0, 1023, 0, 230);
  } else {
    // Adjust brightness (8%–100% to keep LED visible)
    brightness = map(potValue, 0, 1023, 20, 255) / 255.0;
  }

  FastLED.setBrightness(brightness * 255);
  leds[0] = CHSV(hue, 255, 255);
  FastLED.show();

  // --- Serial output (only when values change) ---
  bool changed = false;
  if (modeColor && hue != lastHue) {
    lastHue = hue;
    changed = true;
  } else if (!modeColor && abs(brightness - lastBrightness) > 0.01) {
    lastBrightness = brightness;
    changed = true;
  }

  if (changed) {
    // Convert HSV to RGB for display
    CRGB rgbColor = CHSV(hue, 255, 255);

    Serial.print(F("HSV: ("));
    Serial.print(hue);
    Serial.print(F(", 255, "));
    Serial.print((uint8_t)(brightness * 255));
    Serial.print(F(")  |  RGB: ("));
    Serial.print(rgbColor.r);
    Serial.print(F(", "));
    Serial.print(rgbColor.g);
    Serial.print(F(", "));
    Serial.print(rgbColor.b);
    Serial.print(F(")  |  Brightness: "));
    Serial.print((int)(brightness * 100));
    Serial.println(F("%"));
  }

  delay(20);
}