#pragma once

extern std::vector<uint16_t> melody_steps;

void PublishMqtt(const char * data);

class Player {
public:
	uint16_t id;						  					// The (internal) ID of the selected melody. Not specificly used anywhere atm. Might be used later.
	std::string name = "melody1";       // Name of the Melody saved. Will be used to read the file: /name.bin
	uint16_t speed = 500;               // Time to wait per beat. (In Miliseconds)
  uint32_t duration = 15000;          // Total Duration that program will run (In Miliseconds)
	uint32_t loop_duration = 0;					// Duration of the playback per segment
	uint32_t interval = 0;         			// Indicates the Duration of the Interval between finished segments, IF "inf" is true
  bool infinite_play = false;         // Infinite Loop Indicator (If True the melody will loop forever or until stoped, with pauses of "interval" in between loops)
	bool isPlaying = false;						// Indicates if the Melody is actually Playing right now.
	bool isPaused = false;							// If playing, indicates if the Melody is Paused
	uint64_t startTime = 0;							// The time-point the Melody started Playing
	uint64_t loopStartTime = 0;					// The time-point the current segment started Playing
	bool hardStop = false;							// Flags a hardstop, immediately.
	uint64_t pauseTime = 0;							// The time-point the melody paused

	void play() {
		isPlaying = true;
		hardStop = false;
		startTime = loopStartTime = millis();
		LOG_DEBUG("Plbck: PLAY");
	}

	void forceStop() {
		hardStop = true;
		isPlaying = false;
		LOG_DEBUG("Plbck: FORCE STOP");
	}

	void stop() {
		hardStop = false;
		isPlaying = false;
		LOG_DEBUG("Plbck: STOP");
	}

	void pause() {
		isPaused = true;
		LOG_DEBUG("Plbck: PAUSE");
	}

	void unpause() {
		isPaused = false;
		loopStartTime = millis();
		LOG_DEBUG("Plbck: RESUME");
	}

  // Handles Incoming Commands to PLAY or STOP
  void command(JsonVariant content){
		String action = content["action"];
    LOG_DEBUG("Incoming Command: %s", action);
    if (action == "play") {
      play();
      PublishMqtt("OK - PLAY");
    } else if (action == "stop") {
      forceStop();
      PublishMqtt("OK - STOP");
    }
  }

	// Sets incoming Attributes for the Melody, into the class' variables.
	void setMelodyAttributes(JsonVariant doc){

	  	if (doc.containsKey("name")) {
	  			name = doc["name"].as<const char*>();
	  	}
	  	if (doc.containsKey("id")) {
	  			id = doc["id"].as<uint16_t>();
	  	}
	  	if (doc.containsKey("duration")) {
	  			duration = doc["duration"].as<uint32_t>();
	  	}
	  	if (doc.containsKey("infinite")) {
	  			infinite_play = doc["infinite"].as<bool>();
	  	}
	  	if (doc.containsKey("interval")) {
	  			interval = doc["interval"].as<uint32_t>();
	  	}
	  	if (doc.containsKey("speed")) {
	  			speed = doc["speed"].as<uint16_t>();
	  	}
	  	if (doc.containsKey("loop_dur")) {
	  			loop_duration = doc["loop_dur"].as<uint32_t>();
	  	}
	  	// Print Just for Debugging Purposes
	  	LOG_DEBUG("Name: %s, ID: %d, Total Duration: %lu, Loop Duration: %lu, Interval:  %d, Speed: %d, Inf: %s\n",
	  		name.c_str(),
	  		id,
	  		duration,
	  		loop_duration,
	  		interval,
	  		speed,
	  		infinite_play ? "true" : "false"
	  		);
	}
  

  // Loads the Selected melody from a .bin file on SD into RAM
  void loadMelodyInRAM(std::vector<uint16_t> &melody_steps) {
    String filePath = "/melodies/" + String(name.c_str()) + ".bin";

    File bin_file = SD.open(filePath.c_str(), FILE_READ);
    if (!bin_file) {
        LOG_ERROR("Failed to open file: %s", filePath.c_str());
        return;
    }

    size_t fileSize = bin_file.size();
    if (fileSize % 2 != 0) {
        LOG_ERROR("Invalid file size: %u (not a multiple of 2)", fileSize);
        bin_file.close();
        return;
    }

    melody_steps.resize(fileSize / 2);

    for (size_t i = 0; i < melody_steps.size(); i++) {
        uint8_t high = bin_file.read();
        uint8_t low = bin_file.read();
        melody_steps[i] = (high << 8) | low;
    }

    LOG_INFO("Melody Load Successful");

    bin_file.close();
  }

};
