#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION

#include <dpp/dpp.h>
#include <iostream>
#include <fstream> // Required for file operations
#include <vector> // Required for std::vector
#include <string>

#include "stb_image.h"
#include "stb_image_write.h"
//#include "ImageProcessor.h"

using namespace std;

void flip_image_horizontally(unsigned char* data, int width, int height, int channels);
void flip_image_vertically(unsigned char* data, int width, int height, int channels);
void process_attachment(dpp::cluster& bot, const dpp::message_create_t& event, const dpp::attachment& attachment);

int main() {

	// --- Load the bot token from a file ---
	string token_file_path = "token.txt";

	ifstream token_file(token_file_path);
	string bot_token;
	if (!token_file.is_open()) {
		// if not, try parent directory
		if (!token_file.is_open()) {
			token_file_path = "../token.txt";
			token_file.open(token_file_path);
			if (!token_file.is_open())
			{
				cerr << "ERROR: Could not open token.txt. Please create the file and add your bot token." << std::endl;
        		return 1;
			}
		}		
	}
	getline(token_file, bot_token);
    token_file.close();

	if (bot_token.empty()) {
        std::cerr << "ERROR: Token file is empty. Please add your bot token to token.txt." << std::endl;
        return 1;
    }

    dpp::cluster bot(bot_token, dpp::i_default_intents | dpp::i_message_content);

    bot.on_log(dpp::utility::cout_logger()); // Corrected: no 'true' argument

    std::cout<<"in main"<<endl;
	// Create an instance of your ImageProcessor class
    //ImageProcessor image_processor(bot);

    bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
        std::cout << "Received slash cmd" << std::endl << std::flush; // Keep for testing
        bot.log(dpp::ll_info, "Received slash command: " + event.command.get_command_name());
        if (event.command.get_command_name() == "ping") {
            bot.log(dpp::ll_info, "Processing /ping command. Replying now!");
            event.reply("Pong!");
        } else {
            bot.log(dpp::ll_info, "Received unknown slash command: " + event.command.get_command_name());
        }
    });

    bot.on_ready([&bot](const dpp::ready_t& event) {
        bot.log(dpp::ll_info, "Bot ready. Logged in as: " + bot.me.username);

        if (dpp::run_once<struct register_bot_commands>()) {
            bot.log(dpp::ll_info, "Registering global /ping command...");
            bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id));
        }
    });

	bot.on_message_create([&bot](const dpp::message_create_t& event) {
		// Check if the message has any attachments
		if (!event.msg.attachments.empty()) { //
			// Log that an attachment was found
			bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " contains attachments!");
			
			// You can iterate through the attachments if you need details about each one
			for (const auto& attachment : event.msg.attachments) { //
				bot.log(dpp::ll_info, "  Attachment ID: " + std::to_string(attachment.id) + 
									", Filename: " + attachment.filename + 
									", Size: " + std::to_string(attachment.size) + " bytes");
				// You can also get the URL of the attachment: attachment.url
				// And a proxied URL: attachment.proxy_url
				std::string filename = attachment.filename;
				
				
				if (filename.substr(strlen(filename.c_str())-3,3) == "jpg")
				{
					bot.log(dpp::ll_info, "jpg detected");

					std::string local_filename = "temp_" + attachment.filename;

					process_attachment(bot,event,attachment);
					bot.log(dpp::ll_info, "image flipped horizontally");
					// Download the attachment first
					//download_file(bot, event, attachment.url, local_filename); //

					// Note: The download is asynchronous. You would typically do
					// further processing in the http_request_completion_t handler.
					// For a simple example, you might call load_image from there.
					
				}
			}

			// Example: Reply to the user saying you detected an attachment
			// event.reply("Thanks for the attachment!");
		} else {
			// Log if no attachments were found
			bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " has no attachments.");
		}

		// You can also add logic for processing other types of messages or commands here
	});

    std::cerr << "--- Direct stderr test: Bot is about to start listening ---" << std::endl;

    bot.start(dpp::st_wait);
    return 0;
}

void process_attachment(dpp::cluster& bot, const dpp::message_create_t& event, const dpp::attachment& attachment) {
	std::string local_filename = "temp_" + std::to_string(attachment.id) + "_" + attachment.filename;

	bot.request(attachment.url, dpp::http_method::m_get,
		[ &bot, event, local_filename, attachment](const dpp::http_request_completion_t& completion) {
			if (completion.status < 400) {
				std::ofstream file(local_filename, std::ios::binary);
				if (file.is_open()) {
					file.write(completion.body.c_str(), completion.body.length());
					file.close();

					int width, height, channels;
					//unsigned char* image_data = stbi_load_from_memory(local_filename.c_str(), &width, &height, &channels, 0);
					unsigned char* image_data = stbi_load_from_memory(
						reinterpret_cast<const stbi_uc*>(completion.body.data()),
						completion.body.length(),
						&width, &height, &channels, 0
					);
					if (image_data) {
						// Flip the image horizontally (you can choose which flip to apply)
						bot.log(dpp::ll_info,"channels: " + std::to_string(channels));
						flip_image_horizontally(image_data, width, height, channels);

						// --- Save the flipped image to a new temporary file ---
						std::string flipped_filename = "flipped_" + local_filename;
						stbi_write_jpg(flipped_filename.c_str(), width, height, channels, image_data, 100); // Quality 100

						// --- NEW CODE STARTS HERE ---
						dpp::message msg;
						
						// Add the file to the message
						msg.add_file(flipped_filename, dpp::utility::read_file(flipped_filename));

						// Create an embed and reference the attached file
						dpp::embed embed;
						embed.set_title("Image Info");
						embed.set_description("Dimensions: " + std::to_string(width) + "x" + std::to_string(height));
						embed.set_image("attachment://" + flipped_filename); // Reference the file here
						
						// Add the embed to the message
						msg.add_embed(embed);
						msg.set_channel_id(1398043078559797310);
						bot.message_create(msg);

						msg.set_content("Here's your horizontally flipped image");
						event.reply(msg);
						// --- NEW CODE ENDS HERE ---
						
						stbi_image_free(image_data);
						std::remove(local_filename.c_str());
						std::remove(flipped_filename.c_str()); // Clean up the flipped file
					} else {
						std::cerr << "Error: Failed to load image with stb from " << local_filename << std::endl;
					}
					std::remove(local_filename.c_str());
				} else {
					std::cerr << "Failed to open local file for writing: " << local_filename << std::endl;
				}
			} else {
				std::cerr << "Failed to download image from " << attachment.url << ". HTTP status code: " << completion.status << std::endl;
			}
		});
}

void flip_image_horizontally(unsigned char* data, int width, int height, int channels) {

	for (int y = 0; y < height; ++y) {
		// Get pointers to the start of the current row
		unsigned char* row_start = data + y * width * channels;
		
		// Loop through half the row, swapping pixels from left and right
		for (int x = 0; x < width / 2; ++x) {
			// Calculate the pointers to the left and right pixels
			unsigned char* left_pixel = row_start + x * channels;
			unsigned char* right_pixel = row_start + (width - 1 - x) * channels;
			
			// Swap each channel of the pixels
			for (int c = 0; c < channels; ++c) {
				std::swap(left_pixel[c], right_pixel[c]);
			}
		}
	}
}

void flip_image_vertically(unsigned char* data, int width, int height, int channels) {
	// ... (your vertical flip implementation from before)
	int row_stride = width * channels;
	unsigned char* temp_row = new unsigned char [row_stride];
	for (int y = 0; y < height / 2; ++y) {
		unsigned char* top_row = data + y * row_stride;
		unsigned char* bottom_row = data + (height - 1 - y) * row_stride;
		std::memcpy(temp_row, top_row, row_stride);
		std::memcpy(top_row, bottom_row, row_stride);
		std::memcpy(bottom_row, temp_row, row_stride);
	}
	delete[] temp_row;
}