#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#include "nlohmann/json.hpp"

#include <map>


using json = nlohmann::json;

json workspacesInput, workspacesOutput;

/*json workspacesOutput = json::parse(R"(
	{
		"normal": [
			{
				"occupied": bool,
				"monitorID": int,
				"active": bool,
				"icon": str
			}
		],
		"special": [
			{
				"ID": int,
				"name": str,
				"occupied": bool,
				"monitorID": int,
				"active": bool,
				"icon": str
			}
		]
	}
)");*/

std::map<int, std::string> test;

std::string command(std::string command);
std::string getIcon(std::string windowAddress);




std::string getIcon(std::string windowAddress)
{

	json clients = json::parse(command("hyprctl clients -j"));

	for (json& client : clients)
	{
		
		if (windowAddress == client["address"])
		{
			std::string initClass = client["initialClass"];
			if (initClass == "")
			{
				initClass = "aguiienagi";
			}
			int pid = client["pid"];
			std::string cmd ="cd /home/willifan/.config/eww/scripts/ && ./test.sh ";
			cmd.append(initClass);
			cmd.append(" ");
			cmd.append(std::to_string(pid));
			return command(cmd);
		}

	}

	return "placeholder";

}


json getWorkspace(json workspaceInput, char mode)
{
	json workspaceOutput;

	json monitorsInput = json::parse(command("hyprctl monitors -j"));

	std::string keyValue;

	if (mode == 'n')
	{
		keyValue = "id";
	}
	else if (mode == 's')
	{
		keyValue = "name";
	}

	workspaceOutput[keyValue] = workspaceInput[keyValue];

	for (auto& monitor : monitorsInput)
	{
		if (monitor["activeWorkspace"][keyValue] == workspaceInput[keyValue])
		{
			workspaceOutput["activeOn"] = monitor[keyValue];
		}
	}
	
	workspaceOutput["occupied"] = workspaceInput["windows"];
	
	if (!(workspaceInput["lastwindow"] == "0x0"))
	{
		workspaceOutput["icon"] = getIcon(workspaceInput["lastwindow"]);
	}
	else
	{
		workspaceOutput["icon"] = "";
	}

	return workspaceOutput;

}


json getAllWorkspaces()
{

	workspacesInput = json::parse(command("hyprctl workspaces -j"));

	int specialIndex = 0;

	for(auto& workspace : workspacesInput)
	{
		if(workspace["id"] >= 1 && workspace["id"] <= 9)
		{
			int index = workspace["id"].get<int>() - 1;

			workspacesOutput[index]["normal"].clear();
			workspacesOutput[index]["normal"] = getWorkspace(workspace, 'n');
		}
		else if (std::string(workspace["name"]).find("special:") == 0)
		{
			workspacesOutput[specialIndex]["special"].clear();
			workspacesOutput[specialIndex]["special"] = getWorkspace(workspace, 's');

			specialIndex++;
		}

	}

	return workspacesOutput;

}


std::string command(std::string inputCommand)
{
	const char* command = inputCommand.c_str();
	char buffer[128];
	std::string result;
	FILE* pipe = popen(command, "r");

	if(!pipe)
	{
		std::cerr << "No pipe opened" << std::endl;
		return "";
	}

	while(!feof(pipe))
	{
		if(fgets(buffer, 128, pipe) != NULL)
		{
			result += buffer;
		}
	}

	pclose(pipe);
	return result;
}


void handle(std::string message)
{

	if (message.find("workspace") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	else if (message.find("moveworkspace") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	else if (message.find("openwindow") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	else if (message.find("closewindow") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	else if (message.find("movewindow") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	else if (message.find("activewindow") == 0)
	{
		std::cout << getAllWorkspaces() << std::endl;
	}
	

}

int main(int argc, char const *argv[])
{

	std::cout << getAllWorkspaces() << std::endl;

	std::string socketPath = "/tmp/hypr/" + std::string(std::getenv("HYPRLAND_INSTANCE_SIGNATURE")) + "/.socket2.sock";
	

	// Create a socket
    int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sockfd == -1) {
        std::cerr << "Error: Failed to create socket\n";
        return 1;
    }

    

    // Define the address of the IPC socket
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);

    // Connect to the IPC socket
    if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        std::cerr << "Error: Failed to connect to IPC socket\n";
        close(sockfd);
        return 1;
    }

    // Receive and print messages from the IPC socket
    char buffer[1024];
    ssize_t bytes_received;
    while ((bytes_received = recv(sockfd, buffer, sizeof(buffer), 0)) > 0) {

        std::string message = std::string(buffer, bytes_received);

        std::istringstream iss(message);
        std::string messageLine;

        while(std::getline(iss, messageLine)){
        	handle(messageLine);
        }

    }
    if (bytes_received == -1) {
        std::cerr << "Error: Failed to receive message\n";
    }

    // Close the socket
    close(sockfd);

    return 0;
}