#include <iostream>
#include <cstdlib>
#include <ctime>
#include <random>
#include <chrono>
#include <iomanip>

#include "row.hpp"

using namespace std;
using namespace std::chrono;

template <typename Func>
double measure_sort_time(Func sort_func, row<double>& data) {
	auto start = high_resolution_clock::now();
	sort_func(data);
	auto end = high_resolution_clock::now();

	duration<double, std::milli> duration_ms =  end - start;
	return duration_ms.count();
}

void test_performance(uint32_t n) {
	cout << "\n=== Running Sorting Benchmark for N = " << n << " ===" << endl;

	random_device rd;
	mt19937 gen(rd());
	uniform_real_distribution<double> dis(-10000.0, 10000.0);

	double* base_arr = new double[n];
	for (uint32_t i = 0; i < n; i++) {
		base_arr[i] = dis(gen);
	}

	row<double> original(base_arr, n);
	delete[] base_arr;

	row<double> r_bubble = original;
	row<double> r_selection = original;
	row<double> r_insertion = original;
	row<double> r_merge = original;
	row<double> r_quick = original;
	row<double> r_enumeration = original;

	double t_bubble = measure_sort_time([](row<double>& r){ bubble_sort(r); }, r_bubble);
	double t_selection = measure_sort_time([](row<double>& r){ selection_sort(r); }, r_selection);
	double t_insertion = measure_sort_time([](row<double>& r){ insertion_sort(r); }, r_insertion);
	double t_merge = measure_sort_time([](row<double>& r){ merge_sort(r); }, r_merge);
	double t_quick = measure_sort_time([](row<double>& r){ quick_sort(r); }, r_quick);
	double t_enum = measure_sort_time([](row<double>& r){ enumeration_sort(r);}, r_enumeration);

	cout << left << setw(20) << "Algorithm" << "| " << "Time(ms)" << endl;
	cout<<"---------------------|---------------------"<< endl;
	cout<< left << setw(20) <<"Bubble Sort" << t_bubble << " ms"<<endl;
	cout<< left << setw(20) <<"Selection Sort" << t_selection << " ms"<<endl;
	cout<< left << setw(20) <<"Insertion Sort" << t_insertion << " ms"<<endl;
	cout<< left << setw(20) <<"Merge Sort" << t_merge << " ms"<<endl;
	cout<< left << setw(20) <<"Quick Sort" << t_quick << " ms"<<endl;
	cout<< left << setw(20) <<"Enumeration Sort" << t_enum << " ms"<<endl;
}

int main() {
	srand(time(NULL));

	cout << "---Bubble Sort Implementation--"<<endl;

	int *b = new int[10];
	for (int i=0; i<10; i++) {
		b[i] = rand() % 100;
	}

	row<int> *a = new row<int>(b, 10);

	cout <<"Original Array: "<< *a <<endl;

	bubble_sort(*a);
	cout << "Bubble: " << *a <<endl;

	delete[] b;
	delete a;

	test_performance(1000);
	test_performance(10000);

	return 0;
}
