#include "logging.hpp"
#include <SD.h>
#include <FS.h>
#include <ETH.h>
#include <SPI.h>
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Update.h>
#include <AsyncMqttClient.h>
#include <ArduinoJson.h>
#include <string>
#include <Wire.h>
#include <Adafruit_PCF8574.h>
#include <WebServer.h>
#include <ESPAsyncWebServer.h>
#include <WiFiManager.h>
#include <AsyncUDP.h>
#include <RTClib.h>

// Custom Classes

#include "timekeeper.hpp"

// Hardware Constructors:
Adafruit_PCF8574 relays;
// Wrapper function to connect timekeeper to your relays
void relayWrite(int relayIndex, int state) {
    relays.digitalWrite(relayIndex, state);
}

// SD Card Chip Select:
#define SD_CS 5

// Include Classes
#include "class_player.hpp"

// Class Constructors
Timekeeper timekeeper;
AsyncMqttClient mqttClient;
Player player;
std::vector<uint16_t> melody_steps; // holds the steps of the melody. Should move into bell Engine.
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
AsyncWebSocketClient* activeClient = nullptr;
AsyncUDP udp;
constexpr uint16_t DISCOVERY_PORT = 32101;
uint32_t strikeCounters[16] = {0};
uint16_t bellLoad[16] = {0};
bool coolingActive = false;


#include "config.h"
#include "ota.hpp"
#include "functions.hpp"
#include "commands_handling.hpp"
#include "MQTT_Functions.hpp"
#include "MQTT_Connection_Handling.hpp"
#include "WebSocket_Functions.hpp"
#include "PlaybackControls.hpp"
#include "bellEngine.hpp"
#include "dataLogging.hpp"

TaskHandle_t bellEngineHandle = NULL;
TimerHandle_t schedulerTimer;



void setup()
{
  // Initialize Serial Communications & I2C Bus (for debugging)
	Serial.begin(115200);
	Wire.begin(4,15);
	SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI);
  delay(50);

	// Initialize PCF8574 and Relays
	relays.begin(PCF8574_ADDR, &Wire);
	for (uint8_t p=0; p<6; p++){
		relays.pinMode(p, OUTPUT);
		relays.digitalWrite(p, HIGH);
	}


	// Initialize SD Card
 	if (!SD.begin(SD_CS)) {
    Serial.println("SD card not found. Using defaults.");
  } else {
    // do nothing
  }

	// Initialize timekeeper with NO clock outputs
	 timekeeper.begin();  // No parameters needed
	 // Connect the timekeeper to your relay controller
	 timekeeper.setRelayWriteFunction(relayWrite);
	 timekeeper.setClockOutputs(5, 4);


	// Initialize Networking and MQTT
	Network.onEvent(NetworkEvent);
	ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI);
	InitMqtt();
	WiFiManager wm;
	//wm.resetSettings();  // Only for Debugging.
	bool res;
	res = wm.autoConnect(ap_ssid.c_str(),ap_pass.c_str());
	if(!res) {
			LOG_ERROR("Failed to connect to WiFi");
	}
	else {
			LOG_INFO("Connected to WiFi");
	}

  delay(100);

	checkForUpdates(); // checks for updates online
	setupUdpDiscovery();

	delay(100);

	// WebSocket setup
  ws.onEvent(onWebSocketEvent);
  server.addHandler(&ws);
  // Start the server
  server.begin();

	// Tasks and Timers
  xTaskCreatePinnedToCore(bellEngine,"bellEngine", 8192, NULL, 1, &bellEngineHandle, 1);
  xTaskCreatePinnedToCore(durationTimer, "durationTimer", 8192, NULL, 2, NULL, 1);
	xTaskCreatePinnedToCore(relayControlTask, "Relay Control", 2048, NULL, 2, NULL, 1);
	//xTaskCreatePinnedToCore(dataLogging, "dataLogging", 2048, NULL, 2, NULL, 1);

	loadRelayTimings();
}


void loop()
{
//Serial.printf("b1:%d - b2:%d - Bell 1 Load: %d \n",strikeCounters[0], strikeCounters[1], bellLoad[0]);
}
