#include "led_strip.hpp"
#include "global.hpp"

// LedStrip::LedStrip(/* args */) {}
// LedStrip::~LedStrip() {}

#if defined(ARDUINO_AVR_ATTINYX5) || defined(ARDUINO_AVR_ATTINYX41)
/* TODO: remove when switching to tinycore V2.0.0 */
void LedStrip::fill(uint32_t c, uint16_t first, uint16_t count) {
  uint16_t i, end;

  if (first >= LedCount) {
    return; // If first LED is past end of strip, nothing to do
  }

  // Calculate the index ONE AFTER the last pixel to fill
  if (count == 0) {
    // Fill to end of strip
    end = LedCount;
  } else {
    // Ensure that the loop won't go past the last pixel
    end = first + count;
    if (end > LedCount)
      end = LedCount;
  }

  for (i = first; i < end; i++) {
    setPixelColor(i, c);
  }
}
#endif /* defined(ARDUINO_AVR_ATTINYX5) || defined(ARDUINO_AVR_ATTINYX41) */

void LedStrip::setup() {
  pinMode(LedPin, OUTPUT);
  setPixelColor(0, 255, 0, 0);
  fill(Color(45, 0, 0));
  show();
  delay(300);
  fill(Color(0, 45, 0));
  show();
  delay(300);
  fill(Color(0, 0, 45));
  show();
  delay(300);
}

void LedStrip::refresh() {
  uint16_t const &ledOnMin = ledRingColorState.ledOnMin;
  uint16_t const &ledOnMax = ledRingColorState.ledOnMax;
  uint16_t LedOnCount = 0;

#if defined(__BUILD_DEBUG__)
  debugSerial.print("Color hue,sat,bri=");
  debugSerial.print(ledRingColorState.hue);
  debugSerial.print(",");
  debugSerial.print(ledRingColorState.saturation);
  debugSerial.print(",");
  debugSerial.println(ledRingColorState.brightness);
#endif /* defined(__BUILD_DEBUG__) */

  /* reset ring */
  fill();

  /* compute number of led on */
  if (ledOnMin <= ledOnMax) {
    LedOnCount = ledOnMax - ledOnMin;
  } else {
    LedOnCount = LedCount - (ledOnMax - ledOnMax);
  }

#if defined(__BUILD_DEBUG__)
  debugSerial.print("Led min,max,count=");
  debugSerial.print(ledOnMin);
  debugSerial.print(",");
  debugSerial.print(ledOnMax);
  debugSerial.print(",");
  debugSerial.println(LedOnCount);
#endif /* defined(__BUILD_DEBUG__) */

  for (size_t i = ledRingColorState.ledOnMin; i < ledRingColorState.ledOnMin + LedOnCount; ++i) {
    unsigned int ledId = i;
    if (ledId >= LedCount) {
      ledId -= LedCount;
    }
    setPixelColor(ledId, ColorHSV(ledRingColorState.hue, ledRingColorState.saturation, ledRingColorState.brightness));
  }
  show();
}

void LedStrip::next_preset(void) {
  ++presetState.index;
  if (presetState.index >= PresetMax) {
    presetState.index = 0;
    ++presetState.level;
    if (presetState.level >= PresetLevelMax) {
      presetState.level = 0;
    }
  }
}

void LedStrip::previous_preset(void) {
  --presetState.index;
  if (presetState.index == UINT8_MAX) {
    presetState.index = PresetMax - 1;
    --presetState.level;
    if (presetState.level == UINT8_MAX) {
      presetState.level = PresetLevelMax - 1;
    }
  }
}

void LedStrip::display_led_ring(bool is_preset_enabled) {
  LedRingColorState_t colorState;

  if (is_preset_enabled) {
#if defined(__BUILD_DEBUG__) && false
    debugSerial.print("Preset index,level=");
    debugSerial.print(presetState.index);
    debugSerial.print(",");
    debugSerial.print(presetState.level);
    debugSerial.println();
#endif /* defined(__BUILD_DEBUG__) */
    colorState = {.ledOnMin = this->ledRingColorState.ledOnMin,
                  .ledOnMax = this->ledRingColorState.ledOnMax,
                  .hue = PresetHue[presetState.index],
                  .saturation = (presetState.index == (PresetMax - 1U)) ? 0U : UINT8_MAX,
                  .brightness = PresetBrightness[presetState.level]};
    refresh_led_ring(&colorState);
  } else {
    refresh_led_ring();
  }
}

void LedStrip::refresh_led_ring(LedRingColorState_t const *ledRingColorState) {
  if (ledRingColorState == nullptr) {
    ledRingColorState = &this->ledRingColorState
  }
  uint16_t const &ledOnMin = ledRingColorState.ledOnMin;
  uint16_t const &ledOnMax = ledRingColorState.ledOnMax;
  uint16_t LedOnCount = 0;

#if defined(__BUILD_DEBUG__)
  debugSerial.print("Color hue,sat,bri=");
  debugSerial.print(ledRingColorState.hue);
  debugSerial.print(",");
  debugSerial.print(ledRingColorState.saturation);
  debugSerial.print(",");
  debugSerial.println(ledRingColorState.brightness);
#endif /* defined(__BUILD_DEBUG__) */

  /* reset ring */
  this->fill(0);

  /* compute number of led on */
  if (ledOnMin <= ledOnMax) {
    LedOnCount = ledOnMax - ledOnMin;
  } else {
    LedOnCount = ledCount - (ledOnMax - ledOnMax);
  }

#if defined(__BUILD_DEBUG__)
  debugSerial.print("Led min,max,count=");
  debugSerial.print(ledOnMin);
  debugSerial.print(",");
  debugSerial.print(ledOnMax);
  debugSerial.print(",");
  debugSerial.println(LedOnCount);
#endif /* defined(__BUILD_DEBUG__) */

  for (size_t i = ledRingColorState.ledOnMin; i < ledRingColorState.ledOnMin + LedOnCount; ++i) {
    unsigned int ledId = i;
    if (ledId >= LedCount) {
      ledId -= LedCount;
    }
    ledRing.setPixelColor(ledId, Adafruit_NeoPixel::ColorHSV(ledRingColorState.hue, ledRingColorState.saturation,
                                                             ledRingColorState.brightness));
  }
  ledRing.show();
}

// void display_mode(Mode_e mode) {
//   if (currentMode != Mode_e::ControlOff) {
//     for (size_t i = 0; i < 3; ++i) {
//       fill(0);
//       show();
//       delay(300);
//       for (Mode_e i = Mode_e::Init; i < currentMode; ++i) {
//         setPixelColor(int(i), Adafruit_NeoPixel::ColorHSV(0, 255, 16));
//       }
//       show();
//       delay(300);
//     }
//   }
// }