#pragma once
#include "./basic_types.hpp"
#include "./document_sync.hpp"
#include "./progress.hpp"
#include "./completion.hpp"

namespace lsp::protocol
{
    enum class SymbolKind
    {
        kFile = 1,
        kModule = 2,
        kNamespace = 3,
        kPackage = 4,
        kClass = 5,
        kMethod = 6,
        kProperty = 7,
        kField = 8,
        kConstructor = 9,
        kEnum = 10,
        kInterface = 11,
        kFunction = 12,
        kVariable = 13,
        kConstant = 14,
        kString = 15,
        kNumber = 16,
        kBoolean = 17,
        kArray = 18,
        kObject = 19,
        kKey = 20,
        kNull = 21,
        kEnumMember = 22,
        kStruct = 23,
        kEvent = 24,
        kOperator = 25,
        kTypeParameter = 26
    };

    enum class SymbolTag
    {
        Deprecated = 1
    };

    struct DocumentSymbol
    {
        string name;
        std::optional<string> detail;
        SymbolKind kind;
        std::optional<std::vector<SymbolTag>> tags;
        std::optional<boolean> deprecated;
        Range range;
        Range selectionRange;
        std::optional<std::vector<DocumentSymbol>> children;
    };

    struct SymbolInformation
    {
        string name;
        SymbolKind kind;
        std::optional<std::vector<SymbolTag>> tags;
        std::optional<boolean> deprecated;
        Location location;
        std::optional<string> containerName;
    };

    struct DocumentSymbolClientCapabilities
    {
        struct SymbolKinds
        {
            std::vector<SymbolKind> valueSet;
        };
        struct TagSupport
        {
            std::optional<std::vector<CompletionItemTag>> valueSet;
        };

        std::optional<boolean> dynamicRegistration;
        std::optional<SymbolKinds> symbolKind;
        std::optional<boolean> hierarchicalDocumentSymbolSupport;
        std::optional<TagSupport> tagSupport;
        std::optional<boolean> labelSupport;
    };

    struct DocumentSymbolOptions : WorkDoneProgressOptions
    {
        std::optional<string> label;
    };

    struct DocumentSymbolRegistrationOptions : TextDocumentRegistrationOptions, DocumentSymbolOptions
    {
    };

    struct DocumentSymbolParams : WorkDoneProgressParams, PartialResultParams
    {
        TextDocumentIdentifier textDocument;
    };

    struct WorkspaceSymbolClientCapabilities
    {
        struct SymbolKinds
        {
            std::vector<SymbolKind> valueSet;
        };
        struct TagSupport
        {
            std::optional<std::vector<CompletionItemTag>> valueSet;
        };
        struct ResolveSupport
        {
            std::vector<string> properties;
        };

        std::optional<boolean> dynamicRegistration;
        std::optional<SymbolKinds> symbolKind;
        std::optional<TagSupport> tagSupport;
        std::optional<ResolveSupport> resolveSupport;
    };

    struct WorkspaceSymbolOptions : WorkDoneProgressOptions
    {
        std::optional<boolean> resolveProvider;
    };

    struct WorkspaceSymbolRegistrationOptions : WorkspaceSymbolOptions
    {
    };

    struct WorkspaceSymbolParams : WorkDoneProgressParams, PartialResultParams
    {
        string query;
    };

    struct WorkspaceSymbol
    {
        struct LocationUriOnly
        {
            DocumentUri uri;
        };
        string name;
        SymbolKind kind;
        std::optional<std::vector<SymbolTag>> tags;
        std::optional<string> containerName;
        std::variant<Location, LocationUriOnly> location;
        std::optional<LSPAny> data;
    };

}
