#include "./repo.hpp"

namespace lsp::language::keyword
{
    Repo& Repo::Instance()
    {
        static Repo instance;
        return instance;
    }

    Repo::Repo()
    {
        Load();
    }

    std::vector<Info> Repo::GetAll()
    {
        std::vector<Info> keyword;
        keyword.reserve(keywords_.size());
        for (const auto& [key, value] : keywords_)
            keyword.push_back(value);
        return keyword;
    }

    std::vector<Info> Repo::FindByPrefix(std::string_view prefix)
    {
        std::vector<Info> keyword;
        for (const auto& [key, value] : keywords_)
        {
            if (key.starts_with(prefix))
                keyword.push_back(value);
        }
        return keyword;
    }

    std::optional<Info> Repo::FindByName(std::string_view name)
    {
        auto target = keywords_.find(std::string(name));
        if (target == keywords_.end())
            return std::nullopt;
        return target->second;
    }

    void Repo::Load()
    {
        keywords_.reserve(200);

        LoadProgramStructure();
        LoadDataTypes();
        LoadClasses();
        LoadControlFlow();
        LoadOperators();
        LoadSql();
        LoadBuiltins();
        LoadConstants();
    }

    void Repo::LoadProgramStructure()
    {
        keywords_["program"] = {"program", Kind::kProgramStructure, ""};
        keywords_["function"] = {"function", Kind::kProgramStructure, ""};
        keywords_["procedure"] = {"procedure", Kind::kProgramStructure, ""};
        keywords_["unit"] = {"unit", Kind::kProgramStructure, ""};
        keywords_["uses"] = {"uses", Kind::kProgramStructure, ""};
        keywords_["implementation"] = {"implementation", Kind::kProgramStructure, ""};
        keywords_["interface"] = {"interface", Kind::kProgramStructure, ""};
        keywords_["initialization"] = {"initialization", Kind::kProgramStructure, ""};
        keywords_["finalization"] = {"finalization", Kind::kProgramStructure, ""};
    }

    void Repo::LoadDataTypes()
    {
        keywords_["string"] = {"string", Kind::kDataTypes, ""};
        keywords_["integer"] = {"integer", Kind::kDataTypes, ""};
        keywords_["boolean"] = {"boolean", Kind::kDataTypes, ""};
        keywords_["int64"] = {"int64", Kind::kDataTypes, ""};
        keywords_["real"] = {"real", Kind::kDataTypes, ""};
        keywords_["array"] = {"array", Kind::kDataTypes, ""};
    }

    void Repo::LoadClasses()
    {
        keywords_["type"] = {"type", Kind::kClassTypes, ""};
        keywords_["class"] = {"class", Kind::kClassTypes, ""};
        keywords_["new"] = {"new", Kind::kClassTypes, ""};
    }

    void Repo::LoadControlFlow()
    {
        keywords_["if"] = {"if", Kind::kConditionals, ""};
        keywords_["for"] = {"for", Kind::kLoops, ""};
        keywords_["while"] = {"while", Kind::kLoops, ""};
        keywords_["case"] = {"case", Kind::kConditionals, ""};
    }

    void Repo::LoadOperators()
    {
        keywords_["and"] = {"and", Kind::kLogicalOperators, ""};
        keywords_["or"] = {"or", Kind::kLogicalOperators, ""};
        keywords_["div"] = {"div", Kind::kArithmeticOperators, ""};
        keywords_["mod"] = {"mod", Kind::kArithmeticOperators, ""};
    }

    void Repo::LoadSql()
    {
        keywords_["select"] = {"select", Kind::kSqlControl, ""};
        keywords_["update"] = {"update", Kind::kSqlControl, ""};
    }

    void Repo::LoadBuiltins()
    {
        keywords_["echo"] = {"echo", Kind::kBuiltinFunctions, ""};
        keywords_["mtic"] = {"mtic", Kind::kBuiltinFunctions, ""};
        keywords_["mtoc"] = {"mtoc", Kind::kBuiltinFunctions, ""};
    }

    void Repo::LoadConstants()
    {
        keywords_["true"] = {"true", Kind::kBooleanConstants, ""};
        keywords_["false"] = {"false", Kind::kBooleanConstants, ""};
        keywords_["nil"] = {"nil", Kind::kNullConstants, ""};
        keywords_["inf"] = {"inf", Kind::kMathConstants, ""};
        keywords_["nan"] = {"nan", Kind::kMathConstants, ""};
    }

}
