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

namespace lsp::protocol
{
    enum class CompletionItemTag
    {
        kDeprecated = 1
    };

    enum class InsertTextMode
    {
        kAsIs = 1,
        kAdjustIndentation = 2
    };

    enum class CompletionItemKind
    {
        kText = 1,
        kMethod = 2,
        kFunction = 3,
        kConstructor = 4,
        kField = 5,
        kVariable = 6,
        kClass = 7,
        kInterface = 8,
        kModule = 9,
        kProperty = 10,
        kUnit = 11,
        kValue = 12,
        kEnum = 13,
        kKeyword = 14,
        kSnippet = 15,
        kColor = 16,
        kFile = 17,
        kReference = 18,
        kFolder = 19,
        kEnumMember = 20,
        kConstant = 21,
        kStruct = 22,
        kEvent = 23,
        kOperator = 24,
        kTypeParameter = 25
    };

    enum class InsertTextFormat
    {
        kPlainText = 1,
        kSnippet = 2
    };

    enum CompletionTriggerKind
    {
        kInvoked = 1,
        kTriggerCharacter = 2,
        kTriggerForIncompleteCompletions = 3
    };

    struct CompletionContext
    {
        CompletionTriggerKind triggerKind;
        std::optional<string> triggerCharacter;
    };

    struct InsertReplaceEdit
    {
        string newText;
        Range insert;
        Range replace;
    };

    struct CompletionItemLabelDetails
    {
        std::optional<std::string> detail;
        std::optional<std::string> description;
    };

    struct CompletionItem
    {
        string label;
        std::optional<CompletionItemLabelDetails> labelDetails;
        std::optional<CompletionItemKind> kind;
        std::optional<string> detail;
        std::optional<std::variant<string, MarkupContent>> documentation;
        std::optional<boolean> preselect;
        std::optional<string> sortText;
        std::optional<string> filterText;
        std::optional<string> insertText;
        std::optional<InsertTextFormat> insertTextFormat;
        std::optional<InsertTextMode> insertTextMode;
        std::optional<std::variant<TextEdit, InsertReplaceEdit>> textEdit;
        std::optional<string> textEditText;
        std::optional<std::vector<TextEdit>> additionalTextEdits;
        std::optional<std::vector<string>> commitCharacters;
        std::optional<Command> command;
        std::optional<LSPAny> data;
    };

    struct CompletionList
    {
        struct ItemDefaults
        {
            struct EditRange
            {
                Range insert;
                Range replace;
            };
            std::optional<std::vector<string>> commitCharacters;
            std::optional<std::variant<Range, EditRange>> editRange;
            std::optional<InsertTextFormat> insertTextFormat;
            std::optional<InsertTextMode> insertTextMode;
            std::optional<LSPAny> data;
        };
        boolean isIncomplete;
        ItemDefaults itemDefaults;
        std::vector<CompletionItem> items;
    };

    struct CompletionClientCapabilities
    {
        struct CompletionItem
        {
            struct TagSupport
            {
                std::optional<std::vector<CompletionItemTag>> valueSet;
            };
            struct ResolveSupport
            {
                std::vector<string> properties;
            };
            struct InsertTextModeSupport
            {
                std::optional<std::vector<InsertTextMode>> valueSet;
            };

            boolean snippetSupport;
            std::optional<boolean> commitCharactersSupport;
            std::optional<std::vector<MarkupKind>> documentationFormat;
            std::optional<boolean> deprecatedSupport;
            std::optional<boolean> preselectSupport;
            std::optional<TagSupport> tagSupport;
            boolean insertReplaceSupport;
            ResolveSupport resolveSupport;
            std::optional<InsertTextModeSupport> insertTextModeSupport;
            boolean labelDetailsSupport;
        };
        struct CompletionItemKinds
        {
            std::optional<std::vector<string>> valueSet;
        };
        struct CompletionList
        {
            std::vector<string> itemDefault;
        };

        boolean dynamicRegistration;
        std::optional<CompletionItem> completionItem;
        std::optional<CompletionItemKinds> completionItemKind;
        std::optional<boolean> contextSupport;
        std::optional<InsertTextMode> insertTextMode;
        std::optional<CompletionList> completionList;
    };

    struct CompletionOptions : WorkDoneProgressOptions
    {
        struct CompletionItem
        {
            std::optional<boolean> labelDetailsSupport;
        };
        std::optional<std::vector<string>> triggerCharacters;
        std::optional<std::vector<string>> allCommitCharacters;
        std::optional<boolean> resolveProvider;
        std::optional<CompletionItem> completionItem;
    };
    struct CompletionRegistrationOptions : TextDocumentRegistrationOptions, CompletionOptions
    {
    };
    struct CompletionParams : TextDocumentPositionParams, WorkDoneProgressParams, PartialResultParams
    {
        std::optional<CompletionContext> context;
    };

}
