#include "my_buzzer.h"
#include <FS.h>
#include <LittleFS.h>

#include <anyrtttl.h>
#include <binrtttl.h>
#include <pitches.h>

#include "JsonConstrain.h"

const char* DEFAULT_MELODY = "Ack:d=16,o=5,b=200:c,e,g";

// serial debugging enabled
//#define ANY_RTTTL_INFO

static const char* tag = "buzzer";

BUZZ_TUNE buzzTune[TUNE_MAX_COUNT];
int8_t buzzPin;


void Init_Buzzer(int8_t pin, const char* configFile)
{
  buzzPin = pin;
  if(buzzPin >= 0){
    pinMode(buzzPin, OUTPUT);
  }

  Buzzer_Load_Tunes(configFile); // Load Tunes
  ESP_LOGD(tag, "Buzzer initialized..");
}

void Buzzer_Play_Tune(TUNE_TYPE tune, bool async, bool hasPriority)
{
  static int prev_tune = -1;
  if(buzzPin < 0) return;
  
  if (hasPriority || !anyrtttl::nonblocking::isPlaying()) {
    if (anyrtttl::nonblocking::isPlaying()) {
      anyrtttl::nonblocking::stop();
    }

    // Load nonblocking if different from previous
    if (prev_tune != tune && async) {
      anyrtttl::nonblocking::begin(buzzPin, buzzTune[tune].melody.c_str());
    }

    ESP_LOGD(tag, "Playing tune: %d, melody: %s", tune, buzzTune[tune].melody.c_str());

    for (int c = 0; c < buzzTune[tune].cycles; c++) {
      if (async) {
        anyrtttl::nonblocking::play();
      } else {
        anyrtttl::blocking::play(buzzPin, buzzTune[tune].melody.c_str());
      }
    }

    prev_tune = tune;
  } else {
    ESP_LOGD(tag, "buzzer busy");
  }
}

// TODO Buzzer Beep finish
void Buzzer_Beep(int mSecs, int freq)
{
  /*
  ledcAttachPin(buzzPin, buzzerCh);
  ledcSetup(buzzerCh, 2000, 8);
  ledcWrite(buzzerCh, 125);
  vTaskDelay(mSecs);
  ledcWrite(buzzerCh, 0);
  */
}

// TODO Reduce tunes to load ()
void Buzzer_Load_Tunes(const char* tunesPath){  
  File file = LittleFS.open(tunesPath);

  if (!file) {
      ESP_LOGE(tag, "Error opening %s...", tunesPath);
      return;
  }

  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, file);
  file.close();

  if(error){ 
    ESP_LOGE(tag, "%s deserialize error!..", tunesPath); 
    return;
  }

  JsonArray tuneJsonArray = doc["tunes"];
  if(!tuneJsonArray.isNull()){
    int tuneIndex = 0;
    for(JsonObject obj : tuneJsonArray){
      if(tuneIndex >= TUNE_MAX_COUNT) break;
      buzzTune[tuneIndex].cycles = jsonConstrain<int>(tag, obj, "cycles", 1, 100, 1);
      buzzTune[tuneIndex].pause  = jsonConstrain<int>(tag, obj, "pause", 0, 100, 0);
      buzzTune[tuneIndex].melody =  jsonConstrainString(tag, obj, "tune", DEFAULT_MELODY);
      ESP_LOGD(tag, "tune %d : %s", tuneIndex, buzzTune[tuneIndex].melody.c_str());
      tuneIndex++;
    }
    ESP_LOGI(tag, "Loaded tunes...");
  }else{
    ESP_LOGE(tag, "Error!, %s key: tunes not found..", tunesPath); 
  }
}