#include <Arduino.h>
#include <AceButton.h>
#include <Keyboard.h>
#include <HID.h>
#include <FastLED.h>

// Microsoft PowerToys default: Win + Shift + A
const char HOTKEY_1 = KEY_LEFT_GUI;
const char HOTKEY_2 = KEY_LEFT_SHIFT;
const char HOTKEY_3 = 'a';

#define BUTTON_PIN 2
#define LED_PIN 3
#define NUM_LEDS 4
#define MIN_BRIGHTNESS 32
#define MAX_BRIGHTNESS 255
#define DOUBLECLICK_DELAY 400

using namespace ace_button;
AceButton button(BUTTON_PIN);

CRGB leds[NUM_LEDS];

bool muted = false;
bool ptt = false;

void sendHotkey()
{
  Keyboard.press(HOTKEY_1);
  Keyboard.press(HOTKEY_2);
  Keyboard.press(HOTKEY_3);
  Keyboard.releaseAll();
}

void handleEvent(AceButton * /* button */, uint8_t eventType,
                 uint8_t buttonState)
{

  switch (eventType)
  {
  case AceButton::kEventDoubleClicked:
    if (muted)
    {
      muted = false;
      Serial.println("Toggle: unmuted");
    }
    else
    {
      muted = true;
      Serial.println("Toggle: muted");
    }
    sendHotkey();
    break;
  case AceButton::kEventLongPressed:
    if (muted)
    {
      muted = false;
      Serial.println("PTT: unmuted");
    }
    else
    {
      muted = true;
      Serial.println("PTT: muted");
    }
    ptt = true;
    sendHotkey();
    break;
  case AceButton::AceButton::kEventLongReleased:
    if (muted)
    {
      muted = false;
      Serial.println("PTT: unmuted");
    }
    else
    {
      muted = true;
      Serial.println("PTT: muted");
    }
    ptt = false;
    sendHotkey();
    break;
  }
}

void setupPins()
{
  pinMode(LED_BUILTIN_TX, INPUT); // switch off builtin TX LED
  pinMode(LED_BUILTIN_RX, INPUT); // switch off builtin RX LED
  pinMode(BUTTON_PIN, INPUT_PULLUP);
}

void setupButton()
{
  ButtonConfig *buttonConfig = button.getButtonConfig();
  buttonConfig->setEventHandler(handleEvent);
  buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick);
  buttonConfig->setFeature(ButtonConfig::kFeatureLongPress);
  buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress);
  buttonConfig->setDoubleClickDelay(DOUBLECLICK_DELAY);
  buttonConfig->setLongPressDelay(DOUBLECLICK_DELAY + 1);
}

void setupLEDs()
{
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(MAX_BRIGHTNESS);
  for (size_t i = 0; i < 3; i++)
  {
    for (size_t i = 0; i < NUM_LEDS; i++)
    {
      leds[i] = CRGB::Blue;
      FastLED.show();
      delay(100);
      leds[i] = CRGB::Black;
      FastLED.show();
    }
  }
}

void setup()
{
  Serial.begin(115200);
  delay(500);
  Keyboard.begin();
  setupPins();
  setupButton();
  setupLEDs();
  Serial.flush();
  Serial.println();
  Serial.println("Ultimute ready!");
  Serial.println();
}

void checkButton()
{
  static unsigned long prev = millis();
  unsigned long now = millis();
  if (now - prev > 5)
  {
    button.check();
    prev = now;
  }
}

void handleButtonState()
{
  if (muted)
  {
    FastLED.setBrightness(MIN_BRIGHTNESS);
    fill_solid(leds, NUM_LEDS, CRGB::Green);
  }
  else
  {
    FastLED.setBrightness(MAX_BRIGHTNESS);
    fill_solid(leds, NUM_LEDS, CRGB::Red);
  }

  if (ptt)
  {
    float breath = (exp(sin(millis() / 250.0 * PI)) - 0.36787944) * 108.0;
    breath = map(breath, 0, 255, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
    FastLED.setBrightness(breath);
  }
}

void loop()
{
  checkButton();
  handleButtonState();
  FastLED.show();
}