#include <algorithm>
#include "./location_index.hpp"

namespace lsp::language::symbol
{
    void LocationIndex::AddSymbol(SymbolId id, const ast::Location& location)
    {
        symbol_entries_.push_back({ location.start_byte,
                                    location.end_byte,
                                    id });
        symbols_sorted_ = false;
    }

    void LocationIndex::AddScope(ScopeId id, const ast::Location& range)
    {
        scope_entries_.push_back({ range.start_byte,
                                   range.end_byte,
                                   id });
        scopes_sorted_ = false;
    }

    void LocationIndex::AddReference(SymbolId symbol_id, const ast::Location& location)
    {
        reference_entries_.push_back({ location.start_byte,
                                       location.end_byte,
                                       symbol_id });
        references_sorted_ = false;
    }

    std::optional<SymbolId> LocationIndex::FindSymbolAt(const ast::Location& location) const
    {
        // 确保索引已排序
        if (!symbols_sorted_)
            return std::nullopt;

        return FindInSortedEntries<LocationEntry, SymbolId>(symbol_entries_, location, true);
    }

    std::optional<ScopeId> LocationIndex::FindScopeAt(const ast::Location& location) const
    {
        // 确保索引已排序
        if (!scopes_sorted_)
            return std::nullopt;

        return FindInSortedEntries<ScopeEntry, ScopeId>(scope_entries_, location, true);
    }

    std::optional<SymbolId> LocationIndex::FindReferenceAt(const ast::Location& location) const
    {
        // 确保索引已排序
        if (!references_sorted_)
            return std::nullopt;

        auto it = std::lower_bound(
            reference_entries_.begin(),
            reference_entries_.end(),
            location.start_byte,
            [](const ReferenceEntry& entry, uint32_t pos) {
                return entry.start_byte < pos;
            });

        if (it != reference_entries_.begin())
            --it;

        for (; it != reference_entries_.end() && it->start_byte <= location.start_byte; ++it)
        {
            if (IsLocationInRange(location, it->start_byte, it->end_byte))
                return it->symbol_id;
        }

        return std::nullopt;
    }

    void LocationIndex::RebuildIndex()
    {
        if (!symbols_sorted_)
        {
            std::sort(symbol_entries_.begin(), symbol_entries_.end());
            symbols_sorted_ = true;
        }

        if (!scopes_sorted_)
        {
            std::sort(scope_entries_.begin(), scope_entries_.end());
            scopes_sorted_ = true;
        }

        if (!references_sorted_)
        {
            std::sort(reference_entries_.begin(), reference_entries_.end());
            references_sorted_ = true;
        }
    }

    void LocationIndex::Clear()
    {
        symbol_entries_.clear();
        scope_entries_.clear();
        reference_entries_.clear();
        symbols_sorted_ = true;
        scopes_sorted_ = true;
        references_sorted_ = true;
    }

}
