#include "Arduino.h"
#include "Audio.h"
#include "SD.h"
#include "FS.h"
#include "SPI.h"
#include <ArduinoJson.h>
#include <ezButton.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define USE_UTF8_LONG_NAMES 1
#define SDFATFS_USED
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 3
#define SDFAT_FILE_TYPE 3

// Digital I/O used
#define SD_CS 5

#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18

#define I2S_DOUT 25
#define I2S_BCLK 27
#define I2S_LRC 26
#define TRIGGER_SWITCH 4

#define LED_BUILTIN 2

#define SSD1306_NO_SPLASH 1

Audio audio;
ezButton button(TRIGGER_SWITCH);
TaskHandle_t MainTaskHandle;
TaskHandle_t AudioTaskHandle;

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

struct Config
{
  long delay;
  int volume;
  int debounceTime;
  bool startOnRising;
  char file[64];
  char readyFile[64];
};

const char *filename = "/config.txt";
Config config;

bool flag = true;
bool lastFlag = true;

void cardInfo()
{
  uint8_t cardType = SD.cardType();

  if (cardType == CARD_NONE)
  {
    Serial.println(F("No SD card attached"));
    return;
  }

  Serial.print(F("SD Card Type: "));
  if (cardType == CARD_MMC)
  {
    Serial.println(F("MMC"));
  }
  else if (cardType == CARD_SD)
  {
    Serial.println(F("SDSC"));
  }
  else if (cardType == CARD_SDHC)
  {
    Serial.println(F("SDHC"));
  }
  else
  {
    Serial.println(F("UNKNOWN"));
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

void loadConfiguration(const char *filename, Config &config)
{
  File file = SD.open(filename);

  StaticJsonDocument<1024> doc;

  DeserializationError error = deserializeJson(doc, file);

  if (error)
  {
    Serial.println(F("Failed to read file, using default configuration"));
  }

  config.delay = doc["delay"] | 0;
  config.volume = doc["volume"] | 21;
  config.debounceTime = doc["debounce_time"] | 50;
  config.startOnRising = doc["start_on_rising"] | true;
  strlcpy(config.file, doc["file"] | "beep.mp3", sizeof(config.file));
  strlcpy(config.readyFile, doc["ready_file"] | "beep.mp3", sizeof(config.readyFile));

  file.close();
}

void setTrack(String track)
{
  audio.stopSong();
  audio.connecttoFS(SD, track.c_str());
}

static void AudioTask(void *pvParameters)
{
  while (1)
  {
    Serial.println(F("AudioTask Running"));
    vTaskDelay(config.delay / portTICK_PERIOD_MS);

    Serial.println(F("Play AudioFile"));
    setTrack(config.file);

    vTaskDelete(NULL);
  }

  vTaskDelete(NULL);
}

void start()
{
  xTaskCreate(AudioTask, "AudioTask", 10000, NULL, 1, &AudioTaskHandle);
}

void stop()
{
  audio.stopSong();

  if (AudioTaskHandle != NULL)
  {
    //vTaskDelete(AudioTaskHandle);
  }
}

static void MainTask(void *pvParameters)
{
  while (1)
  {
    audio.loop();
    button.loop();

    if (button.isPressed()) 
    {
      Serial.println(F("TOGGLE HIGH"));

      display.fillRect(122, 2, 4, 4, WHITE);
      display.display();

      if (config.startOnRising != true)
      {
        start();
      }
      else
      {
        stop();
      }
    }

    if (button.isReleased()) 
    {
      Serial.println(F("TOGGLE LOW"));

      display.fillRect(122, 2, 4, 4, BLACK);
      display.display();

      if (config.startOnRising != true)
      {
        stop();
      }
      else
      {
        start();
      }
    }

    vTaskDelay(1 / portTICK_PERIOD_MS);
  }

  vTaskDelete(NULL);
}


void setup()
{
  Serial.begin(115200);

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);

  pinMode(TRIGGER_SWITCH, INPUT_PULLUP);
  //pinMode(TRIGGER_SWITCH, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
  // SPI.setFrequency(1000000);

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  display.clearDisplay();
  display.display();
  //display.drawPixel(10, 10, WHITE);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println(F("Soundcontroller"));

  if (!SD.begin(SD_CS))
  {
    Serial.println(F("Card Mount Failed"));
    return;
  }

  Serial.println(F("Getting CardInfo..."));
  cardInfo();

  Serial.println(F("Loading configuration..."));
  loadConfiguration(filename, config);

  button.setDebounceTime(config.debounceTime);

  Serial.print(F("delay: "));
  Serial.println(config.delay);
  Serial.print(F("volume: "));
  Serial.println(config.volume);
  Serial.print(F("start_on_rising: "));
  Serial.println(config.startOnRising);
  Serial.print(F("ready_file: "));
  Serial.println(config.readyFile);
  Serial.print(F("file: "));
  Serial.println(config.file);


  display.setCursor(0, 20);
  display.println(config.delay);
  display.setCursor(40, 20);
  display.println(config.debounceTime);
  display.setCursor(80, 20);
  display.println(config.volume);
  display.setCursor(120, 20);
  display.println(config.startOnRising);
  display.setCursor(0, 30);
  display.println(config.readyFile);
  display.setCursor(0, 40);
  display.println(config.file);

  display.drawRect(120, 0, 8, 8, WHITE);
  display.fillRect(122, 2, 4, 4, WHITE);
  display.display();

  /*
  File file = SD.open(filename, FILE_READ);

  if (!file) {
      Serial.println("Opening file to read failed");
      return;
  }

  Serial.println("File Content:");

  while (file.available()) {
      Serial.print((char)file.read());
  }
  Serial.println();

  file.close();
  */
  /*
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid.c_str(), password.c_str());

  while (WiFi.status() != WL_CONNECTED) {
     delay(1500);
  }
  */
  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(config.volume); // 0...21

  digitalWrite(LED_BUILTIN, HIGH);

  // audio.connecttoFS(SD, "320k_test.mp3");
  // audio.connecttoFS(SD, "wobble.mp3");
  audio.connecttoFS(SD, config.readyFile);
  // audio.connecttoFS(SD, "220713_Sirenen_VMCStudios_Final.mp3");
  // audio.connecttoFS(SD, "beep.mp3");
  //    audio.connecttohost("http://www.wdr.de/wdrlive/media/einslive.m3u");
  //    audio.connecttohost("http://macslons-irish-pub-radio.com/media.asx");
  //    audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.aac"); //  128k aac
  //    audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.mp3"); //  128k mp3
  //    audio.connecttohost("https://github.com/schreibfaul1/ESP32-audioI2S/raw/master/additional_info/Testfiles/sample1.m4a"); // m4a
  //    audio.connecttohost("https://github.com/schreibfaul1/ESP32-audioI2S/raw/master/additional_info/Testfiles/test_16bit_stereo.wav"); // wav
  //    audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de");

  xTaskCreate(MainTask, "MainTask", 10000, NULL, 1, &MainTaskHandle);
}

void loop()
{
  /*
  audio.loop();
  button.loop();

  if (button.isPressed()) 
  {
    Serial.println(F("TOGGLE HIGH"));

    if (config.startOnRising != true)
    {
      start();
    }
    else
    {
      stop();
    }
  }

  if (button.isReleased()) 
  {
    Serial.println(F("TOGGLE LOW"));

    if (config.startOnRising != true)
    {
      stop();
    }
    else
    {
      start();
    }
  }
  */
  /*
  flag = digitalRead(TRIGGER_SWITCH);

  if (lastFlag != flag)
  {
    lastFlag = flag;

    if (lastFlag == HIGH)
    {
      Serial.println(F("TOGGLE HIGH"));

      if (config.startOnRising == true)
      {
        start();
      }
      else
      {
        stop();
      }
    }
    else
    {
      Serial.println(F("TOGGLE LOW"));

      if (config.startOnRising == false)
      {
        start();
      }
      else
      {
        stop();
      }
    }
  }
  */
}

// optional
void audio_info(const char *info)
{
  Serial.print("info        ");
  Serial.println(info);
}
void audio_id3data(const char *info)
{ // id3 metadata
  Serial.print("id3data     ");
  Serial.println(info);
}
void audio_eof_mp3(const char *info)
{ // end of file
  Serial.print("eof_mp3     ");
  Serial.println(info);
}
void audio_showstation(const char *info)
{
  Serial.print("station     ");
  Serial.println(info);
}
void audio_showstreamtitle(const char *info)
{
  Serial.print("streamtitle ");
  Serial.println(info);
}
void audio_bitrate(const char *info)
{
  Serial.print("bitrate     ");
  Serial.println(info);
}
void audio_commercial(const char *info)
{ // duration in sec
  Serial.print("commercial  ");
  Serial.println(info);
}
void audio_icyurl(const char *info)
{ // homepage
  Serial.print("icyurl      ");
  Serial.println(info);
}
void audio_lasthost(const char *info)
{ // stream URL played
  Serial.print("lasthost    ");
  Serial.println(info);
}
void audio_eof_speech(const char *info)
{
  Serial.print("eof_speech  ");
  Serial.println(info);
}