#pragma once

#include <vector>
#include <hack/logger/logger.hpp>
#include "insertion_sort.hpp"

// Сортировка вставкой
// Эффективна на мелких массивах. Сложнгость O(N^2)
namespace alg_v1
{
  // Функция для слияния двух отсортированных половин массива
  inline void merge(std::vector<int>& v, int start1, int end1, int start2, int end2) 
  {
    auto fs = start1;
    auto fe = end2;

    int i = 1;

    std::vector<int> tmp(v);

    while (start1 <= end1 && (start2 <= end2))
    {
      if (v[start1] < v[start2])
      {
        tmp[i] = v[start1];
        ++start1;
      }
      else
      {
        tmp[i] = v[start2];
        ++start2;
      }
      ++i;
    }

    if (start1 <= end1)
    {
      for (int j = start1; j < end1; ++j)
      {
        tmp[i] = v[j];
        ++i;
      }
    }
    else
    {
      for (int j = start2; j < end2; ++j)
      {
        tmp[i] = v[j];
        ++i;
      }
    }

    i = 1;
    for (int j = fs; j < fe; ++j)
    {
      v[j] = tmp[i];
      ++i;
    }
  }

  inline void merge_sort_helper(int i, std::vector<int>& v, int first, int last) 
  {
    if (first < last) 
    {
      // Находим среднюю точку
      int mid = (first + last) / 2;

      hack::log()(i, " | first =", first, ", last =", last, ", mid =", mid);

      // Сортируем первую и вторую половины
      merge_sort_helper(1, v, first, mid);
      merge_sort_helper(2, v, mid + 1, last);

      // Сливаем отсортированные половины
      merge(v, first, mid, mid + 1, last);
    }
  }

  inline void merge_sort(std::vector<int>& v)
  {
    merge_sort_helper(0, v, 0, v.size() - 1);
  }
}

