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

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

    enum class InsertTextMode
    {
        AsIs = 1,
        AdjustIndentation = 2
    };

    enum class CompletionItemKind
    {
        Text = 1,
        Method = 2,
        Function = 3,
        Constructor = 4,
        Field = 5,
        Variable = 6,
        Class = 7,
        Interface = 8,
        Module = 9,
        Property = 10,
        Unit = 11,
        Value = 12,
        Enum = 13,
        Keyword = 14,
        Snippet = 15,
        Color = 16,
        File = 17,
        Reference = 18,
        Folder = 19,
        EnumMember = 20,
        Constant = 21,
        Struct = 22,
        Event = 23,
        Operator = 24,
        TypeParameter = 25
    };

    enum class InsertTextFormat
    {
        PlainText = 1,
        Snippet = 2
    };

    enum CompletionTriggerKind
    {
        Invoked = 1,
        TriggerCharacter = 2,
        TriggerForIncompleteCompletions = 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<CompletionItemKind>> valueSet;
        };
        struct CompletionList
        {
            std::optional<std::vector<string>> itemDefaults;
            std::optional<boolean> applyKindSupport;
        };

        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;
    };

    struct InlineCompletionClientCapabilities
    {
        std::optional<boolean> dynamicRegistration;
    };

    struct InlineCompletionOptions : WorkDoneProgressOptions
    {
    };

    struct InlineCompletionRegistrationOptions : InlineCompletionOptions, TextDocumentRegistrationOptions, StaticRegistrationOptions
    {
    };

    enum class InlineCompletionTriggerKind
    {
        Invoked = 1,
        Automatic = 2
    };

    struct SelectedCompletionInfo
    {
        Range range;
        string text;
    };

    struct InlineCompletionContext
    {
        InlineCompletionTriggerKind triggerKind;
        std::optional<SelectedCompletionInfo> selectedCompletionInfo;
    };

    struct InlineCompletionParams : TextDocumentPositionParams, WorkDoneProgressParams
    {
        InlineCompletionContext context;
    };

    struct InlineCompletionItem
    {
        std::variant<string, StringValue> insertText;
        std::optional<string> filterText;
        std::optional<Range> range;
        std::optional<Command> command;
    };

    struct InlineCompletionList
    {
        std::vector<InlineCompletionItem> items;
    };
}
