#include WiFi.h>
#include esp_now.h>
#include esp_wifi.h>

// =====================
// PINS
// =====================
const int led1 = 6;
const int led2 = 7;
const int led3 = 8;

const int buttonPin = 9;
const int micPin = 1;
const int buzzerPin = 5;

// =====================
// MIC SETTINGS
// =====================
int threshold = 1000;
bool soundState = false;
unsigned long lastPrint = 0;

// =====================
// BUTTON STATE
// =====================
bool buttonPressed = false;
bool isPlayingSequence = false;

// =====================
// ESP-NOW
// =====================
uint8_t devkitAddress[] = {0x1C, 0xC3, 0xAB, 0xB4, 0x0C, 0xAC};

typedef struct struct_message {
  char command[16];
  int value;
} struct_message;

struct_message incomingMessage;
struct_message outgoingMessage;

volatile bool triggerReceived = false;

// =====================
// CALLBACKS
// =====================
void onDataSent(const wifi_tx_info_t *info, esp_now_send_status_t status) {
  Serial.print("Send status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

void onDataRecv(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
  memcpy(&incomingMessage, incomingData, sizeof(incomingMessage));

  Serial.print("Received command: ");
  Serial.print(incomingMessage.command);
  Serial.print(" | value: ");
  Serial.println(incomingMessage.value);

  if (strcmp(incomingMessage.command, "TRIGGER") == 0) {
    triggerReceived = true;
  }
}

// =====================
// HELPERS
// =====================
void allLedsOff() {
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
}

void allLedsOn() {
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
}

void sendAck() {
  strcpy(outgoingMessage.command, "ACK");
  outgoingMessage.value = 1;

  esp_err_t result = esp_now_send(devkitAddress, (uint8_t *)&outgoingMessage, sizeof(outgoingMessage));

  if (result == ESP_OK) {
    Serial.println("ACK sent");
  } else {
    Serial.print("Error sending ACK: ");
    Serial.println(result);
  }
}

void sendSoundEvent(int micValue) {
  strcpy(outgoingMessage.command, "SOUND");
  outgoingMessage.value = micValue;

  esp_err_t result = esp_now_send(devkitAddress, (uint8_t *)&outgoingMessage, sizeof(outgoingMessage));

  if (result == ESP_OK) {
    Serial.println("SOUND event sent");
  } else {
    Serial.print("Error sending SOUND event: ");
    Serial.println(result);
  }
}

// =====================
// SEQUENCES
// =====================
void playLocalSequence() {
  isPlayingSequence = true;
  Serial.println("Playing LOCAL sequence");

  // LED 1 + low tone
  digitalWrite(led1, HIGH);
  tone(buzzerPin, 523);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led1, LOW);

  // LED 2 + mid tone
  digitalWrite(led2, HIGH);
  tone(buzzerPin, 659);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led2, LOW);

  // LED 3 + high tone
  digitalWrite(led3, HIGH);
  tone(buzzerPin, 784);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led3, LOW);

  isPlayingSequence = false;
}

void playRemoteSequence() {
  isPlayingSequence = true;
  Serial.println("Playing REMOTE sequence");

  // LED 3 + high tone
  digitalWrite(led3, HIGH);
  tone(buzzerPin, 784);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led3, LOW);

  // LED 2 + mid tone
  digitalWrite(led2, HIGH);
  tone(buzzerPin, 659);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led2, LOW);

  // LED 1 + low tone
  digitalWrite(led1, HIGH);
  tone(buzzerPin, 523);
  delay(250);
  noTone(buzzerPin);
  delay(250);
  digitalWrite(led1, LOW);

  isPlayingSequence = false;
}

// =====================
// SETUP
// =====================
void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buzzerPin, OUTPUT);

  Serial.begin(115200);
  delay(1000);

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  esp_wifi_set_promiscuous(true);
  esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);
  esp_wifi_set_promiscuous(false);

  Serial.println("ESP32-C3-Zero - Remote Node");
  Serial.print("My MAC address: ");
  Serial.println(WiFi.macAddress());

  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  esp_now_register_send_cb(onDataSent);
  esp_now_register_recv_cb(onDataRecv);

  esp_now_peer_info_t peerInfo = {};
  memcpy(peerInfo.peer_addr, devkitAddress, 6);
  peerInfo.channel = 1;
  peerInfo.encrypt = false;

  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }

  Serial.println("Peer added successfully");
  Serial.println("Waiting for TRIGGER...");
}

// =====================
// LOOP
// =====================
void loop() {
  int micValue = analogRead(micPin);

  if (millis() - lastPrint >= 1000) {
    Serial.print("Mic value: ");
    Serial.println(micValue);
    lastPrint = millis();
  }

  // Remote trigger from DevKit
  if (triggerReceived) {
    triggerReceived = false;
    playRemoteSequence();
    sendAck();
  }

  // Local button trigger
  if (digitalRead(buttonPin) == LOW && !buttonPressed) {
    buttonPressed = true;
    Serial.println("Local button pressed!");
    playLocalSequence();
  }

  if (digitalRead(buttonPin) == HIGH) {
    buttonPressed = false;
  }

  // Microphone logic only when no sequence is playing
  if (!isPlayingSequence) {
    if (micValue > threshold) {
      allLedsOn();

      if (!soundState) {
        soundState = true;
        Serial.println("Sound detected above threshold");
        sendSoundEvent(micValue);
      }
    } else {
      allLedsOff();
      soundState = false;
    }
  }
}