#ifndef BOUNDED_SCHEDULER_HPP
#define BOUNDED_SCHEDULER_HPP

#include <iostream>
#include <sys/wait.h>
#include <boost/chrono.hpp>
#include <sys/resource.h>
#include <unistd.h>
#include <cstdint>
#include <sched.h>
#include "row.hpp"
#include "sort_algorithms.hpp"

using namespace std;

inline bool bind_process_to_cpu(int cpuId) {
	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	CPU_SET(cpuId, &cpuset);

	int crc = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset);
	if (crc == 0) return true;
	return false;
}

inline uint8_t& PIXEL(uint8_t* video, int f, int i, int j, int k, int H, int W, int C) {

	return video[(((size_t)f * H + i) * W + j) * C + k];
}

class BoundedProlificScheduler {
public:
	static void execute(uint8_t* video, int actualFrames, int H, int W, int C, int numCPUs) {
		pid_t root = getpid();
		int active_children = 0;
		int max_concurrent = numCPUs;

		cout << "\n=== Bounded Video Prolific Scheduler Begins ===" << endl;
		cout << "[Parent " << root << "] Max concurrent workers (Bound): " << max_concurrent <<endl;

		boost::chrono::high_resolution_clock::time_point t1 = boost::chrono::high_resolution_clock::now();
		


		for (int next_frame = 0; next_frame < actualFrames; next_frame++) {

			if (active_children >= max_concurrent) {
				int status;
				if (waitpid(-1, &status, 0) > 0) {
					active_children--;
				}

			}

			pid_t pid = fork();

			if (pid < 0) {
				perror("fork failed");
				return;
			}

			if (pid == 0) {
				pid_t mypid = getpid();

				int childCpu = (next_frame % numCPUs);
				bind_process_to_cpu(childCpu);
				setpriority(PRIO_PROCESS, 0, -5);

				cout<< "[Worker PID " << mypid << " | CPU " << childCpu << "] Sorting frame " << next_frame << ". . ." <<endl;

				for (int i = 0; i < H; i++) {
					uint8_t* blueRow = new uint8_t[W];
					uint8_t* greenRow = new uint8_t[W];
					uint8_t* redRow = new uint8_t[W];

					for (int j = 0; j < W; j++) {
						blueRow[j] = PIXEL(video, next_frame, i, j, 0, H, W, C);
						greenRow[j] = PIXEL(video, next_frame, i, j, 1, H, W, C);
						redRow[j] = PIXEL(video, next_frame, i, j, 2, H, W, C);
					}

					row<uint8_t> b(blueRow, W);
					row<uint8_t> g(greenRow, W);
					row<uint8_t> r(redRow, W);

					quick_sort(b);
					quick_sort(g);
					quick_sort(r);

					for (int j = 0; j < W; j++) {
						PIXEL(video, next_frame, i, j, 0, H, W, C) = b[j];
						PIXEL(video, next_frame, i, j, 1, H, W, C) = g[j];
						PIXEL(video, next_frame, i, j, 2, H, W, C) = r[j];
					}

					delete[] blueRow;
					delete[] greenRow;
					delete[] redRow;
				}
				_exit(0);
			}
			else if (pid > 0) {
				active_children++;
			}
		}

		cout <<"\nParent " << root << "] All frames dispatched. Waiting for remaining " << active_children << " workers to finish..."<<endl;

		while (active_children > 0) {
			int status;
			if (waitpid(-1, &status, 0) > 0) {
				active_children--;
			}
		}

		boost::chrono::high_resolution_clock::time_point t2 = boost::chrono::high_resolution_clock::now();
		boost::chrono::milliseconds ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(t2 - t1);

		cout << "[Parent " << root << "] All frames processed successfully." << endl;
		cout << "Total execution time: " << ms.count() << " ms "<< endl;
	}
};
#endif
