#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include <string>
#include <iomanip>
#include "algorithm.h"
#include "out.h"

using namespace std;

#define UP_BOUND 1000000

// Function pointer for sorting algorithms
typedef void (*SortFunction)(vector<int>&, long long&, long long&);

bool is_sorted(const vector<int>& vec)
{
    for (size_t i = 0; i < vec.size() - 1; ++i)
    {
        if (vec[i] > vec[i + 1])
        {
            return false;
        }
    }
    return true;
}

void run_performance_analysis()
{
    cout << "--- Running Performance Analysis ---" << endl;
    
    SortFunction algorithms[] = {InsertSort, BubbleSort, ShellSort, MergeSort, QuickSort, QuickSortOptimized, QuickSort3Way, DualPivotQuickSort};
    string algo_names[] = {"InsertSort", "BubbleSort", "ShellSort", "MergeSort", "QuickSort", "QuickSortOpt", "QuickSort3Way", "DualPivotSort"};
    int num_algorithms = sizeof(algorithms) / sizeof(algorithms[0]);

    vector<int> sizes = {100, 1000, 10000, 50000, 100000, 500000};
    int num_repeats = 10;

    cout << left << setw(15) << "Algorithm"
         << setw(10) << "Size"
         << setw(20) << "Avg Time (s)"
         << setw(25) << "Avg Comparisons"
         << setw(25) << "Avg Moves"
         << setw(15) << "Correct?" << endl;
    cout << string(110, '-') << endl;

    for (int i = 0; i < num_algorithms; i++)
    {
        for (int size : sizes)
        {
            if (size >= 50000 && (algo_names[i] == "InsertSort" || algo_names[i] == "BubbleSort"))
            {
                cout << left << setw(15) << algo_names[i]
                     << setw(10) << size << " -> Skipped" << endl;
                continue; 
            }

            double total_time = 0;
            long long total_comps = 0;
            long long total_moves = 0;
            bool all_correct = true;

            for (int j = 0; j < num_repeats; j++)
            {
                vector<int> vec(size);
                for (int k = 0; k < size; k++)
                    vec[k] = rand() % UP_BOUND;

                long long comp_count = 0;
                long long move_count = 0;
                
                vector<int> temp_vec = vec;

                clock_t start_time = clock();
                algorithms[i](temp_vec, comp_count, move_count);
                clock_t end_time = clock();

                if (!is_sorted(temp_vec))
                {
                    all_correct = false;
                }

                total_time += (double)(end_time - start_time) / CLOCKS_PER_SEC;
                total_comps += comp_count;
                total_moves += move_count;
            }

            cout << left << setw(15) << algo_names[i]
                 << setw(10) << size
                 << fixed << setprecision(6) << setw(20) << total_time / num_repeats
                 << setw(25) << total_comps / num_repeats
                 << setw(25) << total_moves / num_repeats
                 << setw(15) << (all_correct ? "Yes" : "No") << endl;
        }
        cout << endl;
    }
    cout << "------------------------------------" << endl;
}


int main()
{
    srand(time(0)); // Seed for random number generation

    run_performance_analysis();

    return 0;
}
