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

namespace lsp::language::symbol
{
    SymbolId SymbolDefinitionStore::Add(SymbolDefinition def)
    {
        def.id = next_id_++;
        UpdateIndices(def);
        definitions_[def.id] = std::move(def);
        return def.id;
    }

    const SymbolDefinition* SymbolDefinitionStore::Get(SymbolId id) const
    {
        auto it = definitions_.find(id);
        return it != definitions_.end() ? &it->second : nullptr;
    }

    bool SymbolDefinitionStore::Update(SymbolId id, std::function<void(SymbolDefinition&)> updater)
    {
        auto it = definitions_.find(id);
        if (it == definitions_.end())
            return false;

        RemoveFromIndices(it->second);
        updater(it->second);
        UpdateIndices(it->second);
        return true;
    }

    bool SymbolDefinitionStore::Remove(SymbolId id)
    {
        auto it = definitions_.find(id);
        if (it == definitions_.end())
            return false;

        RemoveFromIndices(it->second);
        definitions_.erase(it);
        return true;
    }

    std::vector<const SymbolDefinition*> SymbolDefinitionStore::GetAll() const
    {
        std::vector<const SymbolDefinition*> result;
        result.reserve(definitions_.size());
        for (const auto& [id, def] : definitions_)
            result.push_back(&def);
        return result;
    }

    std::vector<const SymbolDefinition*> SymbolDefinitionStore::FindByName(const std::string& name) const
    {
        std::vector<const SymbolDefinition*> result;
        auto it = name_index_.find(name);
        if (it != name_index_.end())
        {
            for (SymbolId id : it->second)
            {
                if (auto def = Get(id))
                    result.push_back(def);
            }
        }
        return result;
    }

    std::vector<SymbolId> SymbolDefinitionStore::GetChildren(SymbolId parent_id) const
    {
        auto it = children_index_.find(parent_id);
        return it != children_index_.end() ? it->second : std::vector<SymbolId>{};
    }

    void SymbolDefinitionStore::Clear()
    {
        definitions_.clear();
        name_index_.clear();
        children_index_.clear();
        next_id_ = 1;
    }

    void SymbolDefinitionStore::UpdateIndices(const SymbolDefinition& def)
    {
        name_index_[def.name].push_back(def.id);

        if (def.parent_id)
            children_index_[*def.parent_id].push_back(def.id);
    }

    void SymbolDefinitionStore::RemoveFromIndices(const SymbolDefinition& def)
    {
        auto& name_vec = name_index_[def.name];
        name_vec.erase(std::remove(name_vec.begin(), name_vec.end(), def.id), name_vec.end());

        if (def.parent_id)
        {
            auto& children_vec = children_index_[*def.parent_id];
            children_vec.erase(std::remove(children_vec.begin(), children_vec.end(), def.id), children_vec.end());
        }
    }

}
