#include <WiFi.h>
#include <HTTPClient.h>
#include "ArduinoJson.h"
#include "SD.h"
#include "SPI.h"

// Pin configuration
#define SD_CS_PIN 5
#define SPEAKER_PIN 25

#define UPDATE_INTERVAL 5 * 1000  // (5 sec)

// SD card file
File audioFile;

bool azan = false;

unsigned long previousMillis_Upadte = 0;  // will store last time updated

int fajrHour, fajrMinute, dhuhrHour, dhuhrMinute, asrHour, asrMinute, maghribHour, maghribMinute, ishaHour, ishaMinute;

// User WiFi details
const char* WIFI_SSID = "ooredooBA902F";         // Replace with your Wi-Fi network name (SSID)
const char* WIFI_PASSWORD = "P@SWRD4WIFIEZ123";  // Replace with your Wi-Fi network password

const char* dataTimingsFajr;
const char* dataTimingsSunrise;
const char* dataTimingsDhuhr;
const char* dataTimingsAsr;
const char* dataTimingsMaghrib;
const char* dataTimingsIsha;

// User defined location details
String USER_LATITUDE = "33.88";
String USER_LONGITUDE = "10.08";

// Will be updated with JSON
String CURRENT_TIMEZONE = "Africa/Tunis";
String CURRENT_DATE = "01-01-2000";
String CURRENT_TIME = "00:00:00";
int CURRENT_MINUTE;
int CURRENT_HOUR;

// Function prototypes
void initializeSDCard();
void connectToWiFi();
void getTimezone();
void getPrayerTimes();
void openAudioFile();
void playAudioFile();
void checkAzan();
void extractHourMinute();
void convertTime2int();
void checkNextPrayer();

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(115200);  // Start serial communication at 115200 baud
  while (!Serial) {
    // wait for serial port to connect.
  }

  // Initialize SD card
  initializeSDCard();

  // Open audio file
  openAudioFile();

  // Set speaker pin as output
  pinMode(SPEAKER_PIN, OUTPUT);
  digitalWrite(SPEAKER_PIN, LOW);

  Serial.println(" * Prayer Time * ");  // Print once

  connectToWiFi();
}

void loop() {
  unsigned long currentMillis = millis();

  if (azan == false) {
    if (WiFi.status() == WL_CONNECTED) {
      if (currentMillis - previousMillis_Upadte >= UPDATE_INTERVAL) {
        getTimezone();
        getPrayerTimes();
        checkAzan();
        convertTime2int();
        checkNextPrayer();

        // save the last time
        previousMillis_Upadte = currentMillis;
      }
    } else {
      Serial.println("Lost connection!");
      delay(500);
      connectToWiFi();
    }
  } else {
    playAudioFile();
    // When End of audio file reached
    // azan = false
    // Re-connect to wifi
    // Take a look at playAudioFile()
  }
}

void connectToWiFi() {
  // Connect to Wi-Fi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("Wi-Fi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void getTimezone() {
  WiFiClient client;
  HTTPClient http;

  // Make request to the URL
  String url = "http://worldtimeapi.org/api/timezone/" + CURRENT_TIMEZONE;
  http.begin(client, url);

  // Send the GET request
  int httpResponseCode = http.GET();

  if (httpResponseCode > 0) {
    String response = http.getString();

    StaticJsonDocument<768> doc;
    DeserializationError error = deserializeJson(doc, response);

    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      return;
    }

    const char* datetime = doc["datetime"];  // "2023-06-22T12:22:35.847564+01:00"

    // Extract date
    char dateBuffer[11];
    strncpy(dateBuffer, datetime, 10);
    dateBuffer[10] = '\0';

    CURRENT_DATE = dateBuffer;

    // Extract time
    char timeBuffer[6];  // Buffer to hold time component (HH:MM + null terminator)
    strncpy(timeBuffer, datetime + 11, 5);
    timeBuffer[5] = '\0';  // Add null terminator

    CURRENT_TIME = timeBuffer;

    // Extract hour
    char hourBuffer[3];  // Buffer to hold hour component (HH + null terminator)
    strncpy(hourBuffer, datetime + 11, 2);
    hourBuffer[2] = '\0';  // Add null terminator

    CURRENT_HOUR = atoi(hourBuffer);

    // Extract minute
    char minuteBuffer[3];  // Buffer to hold minute component (MM + null terminator)
    strncpy(minuteBuffer, datetime + 14, 2);
    minuteBuffer[2] = '\0';  // Add null terminator

    CURRENT_MINUTE = atoi(hourBuffer);

    Serial.println();
    Serial.println(CURRENT_DATE);
    Serial.println(CURRENT_TIME);

    JsonObject dataMeta = doc["meta"];
    const char* dataMetaTimezone = dataMeta["timezone"];

    CURRENT_TIMEZONE = dataMetaTimezone;

    // Close HTTP connection
    http.end();
  } else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
}

void getPrayerTimes() {
  WiFiClient client;
  HTTPClient http;

  // Make request to the URL
  String url = "http://api.aladhan.com/v1/timings/" + CURRENT_DATE + "?latitude=" + USER_LATITUDE + "&longitude=" + USER_LONGITUDE + "&method=1";
  http.begin(client, url);

  // Send the GET request
  int httpResponseCode = http.GET();

  if (httpResponseCode > 0) {
    String response = http.getString();

    DynamicJsonDocument doc(3072);
    DeserializationError error = deserializeJson(doc, response);

    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      return;
    }

    int code = doc["code"];
    const char* status = doc["status"];

    JsonObject data = doc["data"];

    JsonObject dataTimings = data["timings"];
    dataTimingsFajr = dataTimings["Fajr"];
    dataTimingsSunrise = dataTimings["Sunrise"];
    dataTimingsDhuhr = dataTimings["Dhuhr"];
    dataTimingsAsr = dataTimings["Asr"];
    dataTimingsMaghrib = dataTimings["Maghrib"];
    dataTimingsIsha = dataTimings["Isha"];

    //Debug
    //dataTimingsFajr = "10:35";

    JsonObject dataMeta = data["meta"];
    const char* dataMetaTimezone = dataMeta["timezone"];

    CURRENT_TIMEZONE = dataMetaTimezone;

    // Print prayer times for the current date and location (RAW data)
    Serial.println();
    Serial.print("Prayer     ");
    Serial.print("Time   ");
    Serial.println();
    Serial.println("----------------");
    Serial.print("Fajr       ");
    Serial.print(dataTimingsFajr);
    Serial.println();
    Serial.print("Sunrise    ");
    Serial.print(dataTimingsSunrise);
    Serial.println();
    Serial.print("Dhuhr      ");
    Serial.print(dataTimingsDhuhr);
    Serial.println();
    Serial.print("Asr        ");
    Serial.print(dataTimingsAsr);
    Serial.println();
    Serial.print("Maghrib    ");
    Serial.print(dataTimingsMaghrib);
    Serial.println();
    Serial.print("Isha       ");
    Serial.print(dataTimingsIsha);
    Serial.println();

    // Close HTTP connection
    http.end();
  } else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
}

// Initialize the SD card
void initializeSDCard() {
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("SD card initialization failed!");
    delay(500);
    SD.begin(SD_CS_PIN);
  }
}

// Open the audio file
void openAudioFile() {
  audioFile = SD.open("/path/to/audio_8.wav");
  if (!audioFile) {
    Serial.println("Error opening audio file!");
    delay(100);
    for (int i = 0; i < 5; i++) {
      audioFile = SD.open("/path/to/audio_8.wav");
      delay(10);
    }
  }
}

// Play audio data from the file
void playAudioFile() {
  int audioSample = audioFile.read();

  if (audioSample == -1) {
    // End of audio file reached
    Serial.println("End of audio file reached!");
    audioFile.close();
    // get back to normal mode
    azan = false;
    connectToWiFi();
  }

  // Repeat outputing sound for better quality
  for (int i = 0; i < 10; i++) {
    // Write audio sample to speaker pin
    dacWrite(SPEAKER_PIN, audioSample);
  }
}

void checkAzan() {
  if (CURRENT_TIME == dataTimingsFajr || CURRENT_TIME == dataTimingsDhuhr || CURRENT_TIME == dataTimingsAsr || CURRENT_TIME == dataTimingsMaghrib || CURRENT_TIME == dataTimingsIsha) {
    // Play audio data from SD card file
    azan = true;
    Serial.println("Azan is playing");
  } else {
    digitalWrite(SPEAKER_PIN, LOW);
  }
}

void extractHourMinute(const char* prayerTime, int& hour, int& minute) {
  // Get 2 character hour string from prayer time string
  char hourBuffer[3];
  strncpy(hourBuffer, prayerTime + 0, 2);
  hourBuffer[2] = '\0';

  // Convert hour string to integer
  hour = atoi(hourBuffer);

  // Get 2 character minute string
  char minuteBuffer[3];
  strncpy(minuteBuffer, prayerTime + 3, 2);
  minuteBuffer[2] = '\0';

  // Convert minute string to integer
  minute = atoi(minuteBuffer);
}

void convertTime2int() {
  extractHourMinute(dataTimingsFajr, fajrHour, fajrMinute);
  Serial.println();
  Serial.print("Fajr hour: ");
  Serial.print(fajrHour);
  Serial.print(" minute: ");
  Serial.println(fajrMinute);


  extractHourMinute(dataTimingsDhuhr, dhuhrHour, dhuhrMinute);
  Serial.print("Dhuhr hour: ");
  Serial.print(dhuhrHour);
  Serial.print(" minute: ");
  Serial.println(dhuhrMinute);

  extractHourMinute(dataTimingsAsr, asrHour, asrMinute);
  Serial.print("Asr hour: ");
  Serial.print(asrHour);
  Serial.print(" minute: ");
  Serial.println(asrMinute);

  extractHourMinute(dataTimingsMaghrib, maghribHour, maghribMinute);
  Serial.print("Maghrib hour: ");
  Serial.print(maghribHour);
  Serial.print(" minute: ");
  Serial.println(maghribMinute);

  extractHourMinute(dataTimingsIsha, ishaHour, ishaMinute);
  Serial.print("Isha hour: ");
  Serial.print(ishaHour);
  Serial.print(" minute: ");
  Serial.println(ishaMinute);
}

void checkNextPrayer() {
  int nextPrayer = 0;
  int nextPrayerHour = 0;
  int nextPrayerMinute = 0;

  if (CURRENT_HOUR < fajrHour) {
    nextPrayer = 1;
    nextPrayerHour = fajrHour;
    nextPrayerMinute = fajrMinute;
  } else if (CURRENT_HOUR < dhuhrHour) {
    nextPrayer = 2;
    nextPrayerHour = dhuhrHour;
    nextPrayerMinute = dhuhrMinute;
  } else if (CURRENT_HOUR < asrHour) {
    nextPrayer = 3;
    nextPrayerHour = asrHour;
    nextPrayerMinute = asrMinute;
  } else if (CURRENT_HOUR < maghribHour) {
    nextPrayer = 4;
    nextPrayerHour = maghribHour;
    nextPrayerMinute = maghribMinute;
  } else {
    nextPrayer = 5;
    nextPrayerHour = ishaHour;
    nextPrayerMinute = ishaMinute;
  }

  Serial.println();
  Serial.print("Next prayer is: ");
  if (nextPrayer == 1) Serial.println("Fajr");
  else if (nextPrayer == 2) Serial.println("Dhuhr");
  else if (nextPrayer == 3) Serial.println("Asr");
  else if (nextPrayer == 4) Serial.println("Maghrib");
  else if ((nextPrayer == 5) && ((nextPrayerHour) != 0)) Serial.println("Isha");

  if ((nextPrayer == 5) && ((nextPrayerHour) == 0)) {  //When error occurs converting from String to int print :
    Serial.print("CURRENT_TIME : ");
    Serial.println(CURRENT_TIME);
  } else {
    Serial.print("Time: ");
    Serial.print(nextPrayerHour);
    Serial.print(":");
    Serial.println(nextPrayerMinute);
  }
}

This is the final code. Add comments// and header /* Description */, look for unused variables/functions, define function prototypes if it's not defined, If needed change variable names and function only if needed.