#include "binary_heap.h"
#include "../index/priority_queue.h"
#include <algorithm>

template<typename T, typename Comparator>
void BinaryHeap<T, Comparator>::sift_up(size_t idx) {
    while (idx > 0) {
        size_t parent = (idx - 1) / 2;
        if (comp_(heap_[idx], heap_[parent], items_)) {
            std::swap(heap_[idx], heap_[parent]);
            idx = parent;
        } else {
            break;
        }
    }
}

template<typename T, typename Comparator>
void BinaryHeap<T, Comparator>::sift_down(size_t idx) {
    const size_t n = heap_.size();
    while (true) {
        size_t smallest = idx;
        size_t left = 2 * idx + 1;
        size_t right = 2 * idx + 2;
        
        if (left < n && comp_(heap_[left], heap_[smallest], items_)) {
            smallest = left;
        }
        if (right < n && comp_(heap_[right], heap_[smallest], items_)) {
            smallest = right;
        }
        
        if (smallest != idx) {
            std::swap(heap_[idx], heap_[smallest]);
            idx = smallest;
        } else {
            break;
        }
    }
}

template<typename T, typename Comparator>
BinaryHeap<T, Comparator>::BinaryHeap(const std::vector<T>& items, Comparator comp)
    : items_(items), comp_(comp) {}

template<typename T, typename Comparator>
void BinaryHeap<T, Comparator>::build(const std::vector<size_t>& indices) {
    heap_ = indices;
    
    // Heapify from bottom up
    for (int i = static_cast<int>(heap_.size()) / 2 - 1; i >= 0; --i) {
        sift_down(static_cast<size_t>(i));
    }
}

template<typename T, typename Comparator>
size_t BinaryHeap<T, Comparator>::pop() {
    if (heap_.empty()) {
        return SIZE_MAX;
    }
    
    size_t result = heap_[0];
    heap_[0] = heap_.back();
    heap_.pop_back();
    
    if (!heap_.empty()) {
        sift_down(0);
    }
    
    return result;
}

template<typename T, typename Comparator>
std::vector<size_t> BinaryHeap<T, Comparator>::sorted() const {
    std::vector<size_t> result = heap_;
    std::vector<size_t> sorted_result;
    sorted_result.reserve(result.size());
    
    // Create a copy to use for sifting
    std::vector<T> items_copy(items_);
    BinaryHeap<T, Comparator> temp_heap(items_copy, comp_);
    temp_heap.build(result);
    
    while (!temp_heap.empty()) {
        sorted_result.push_back(temp_heap.pop());
    }
    
    return sorted_result;
}

// Explicit instantiation for IndexEntry type used in priority queue
template class BinaryHeap<IndexEntry, EntryComparator>;
