#pragma once
#include "LibLsp/lsp/method_type.h"

#include <stdexcept>
#include "LibLsp/JsonRpc/message.h"
#include "LibLsp/lsp/lsDocumentUri.h"
#include "LibLsp/lsp/lsAny.h"
#include "LibLsp/lsp/extention/jdtls/searchSymbols.h"
#include "lsWorkspaceClientCapabilites.h"
#include "LibLsp/lsp/lsp_completion.h"
#include "LibLsp/lsp/lsp_diagnostic.h"

struct WorkDoneProgressOptions
{
    optional<bool> workDoneProgress;
    MAKE_SWAP_METHOD(WorkDoneProgressOptions, workDoneProgress);
};
MAKE_REFLECT_STRUCT(WorkDoneProgressOptions, workDoneProgress);

// Completion options.
struct lsCompletionOptions : WorkDoneProgressOptions
{
    // The server provides support to resolve additional
    // information for a completion item.
    optional<bool> resolveProvider = false;

    //
    // Most tools trigger completion request automatically without explicitly requesting
    // it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user
    // starts to type an identifier. For example if the user types `c` in a JavaScript file
    // code complete will automatically pop up present `console` besides others as a
    // completion item. Characters that make up identifiers don't need to be listed here.
    //
    // If code complete should automatically be trigger on characters not being valid inside
    // an identifier (for example `.` in JavaScript) list them in `triggerCharacters`.
    //
    // https://github.com/Microsoft/language-server-protocol/issues/138.
    optional<std::vector<std::string>> triggerCharacters;

    //
    // The list of all possible characters that commit a completion. This field can be used
    // if clients don't support individual commmit characters per completion item. See
    // `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport`
    //
    optional<std::vector<std::string>> allCommitCharacters;

    MAKE_SWAP_METHOD(lsCompletionOptions, workDoneProgress, resolveProvider, triggerCharacters, allCommitCharacters);
};
MAKE_REFLECT_STRUCT(lsCompletionOptions, workDoneProgress, resolveProvider, triggerCharacters, allCommitCharacters);

// Save options.
struct lsSaveOptions
{
    // The client is supposed to include the content on save.
    bool includeText = false;
    void swap(lsSaveOptions& arg) noexcept
    {
        auto temp = includeText;
        includeText = arg.includeText;
        arg.includeText = temp;
    }
};
MAKE_REFLECT_STRUCT(lsSaveOptions, includeText);

// Signature help options.
struct lsSignatureHelpOptions : WorkDoneProgressOptions
{
    // The characters that trigger signature help automatically.
    // NOTE: If updating signature help tokens make sure to also update
    // WorkingFile::FindClosestCallNameInBuffer.
    std::vector<std::string> triggerCharacters;
    MAKE_SWAP_METHOD(lsSignatureHelpOptions, workDoneProgress, triggerCharacters);
};
MAKE_REFLECT_STRUCT(lsSignatureHelpOptions, workDoneProgress, triggerCharacters);

// Defines how the host (editor) should sync document changes to the language
// server.
enum class lsTextDocumentSyncKind
{
    // Documents should not be synced at all.
    None = 0,

    // Documents are synced by always sending the full content
    // of the document.
    Full = 1,

    // Documents are synced by sending the full content on open.
    // After that only incremental updates to the document are
    // send.
    Incremental = 2
};

#if _WIN32
MAKE_REFLECT_TYPE_PROXY(lsTextDocumentSyncKind)
#else
//#pragma clang diagnostic push
//#pragma clang diagnostic ignored "-Wunused-function"
MAKE_REFLECT_TYPE_PROXY(lsTextDocumentSyncKind)
//#pragma clang diagnostic pop
#endif

struct lsTextDocumentSyncOptions
{
    // Open and close notifications are sent to the server.
    optional<bool> openClose;
    // Change notificatins are sent to the server. See TextDocumentSyncKind.None,
    // TextDocumentSyncKind.Full and TextDocumentSyncKindIncremental.
    optional<lsTextDocumentSyncKind> change;
    // Will save notifications are sent to the server.
    optional<bool> willSave;
    // Will save wait until requests are sent to the server.
    optional<bool> willSaveWaitUntil;
    // Save notifications are sent to the server.
    optional<lsSaveOptions> save;

    MAKE_SWAP_METHOD(lsTextDocumentSyncOptions, openClose, change, willSave, willSaveWaitUntil, save);
};
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, openClose, change, willSave, willSaveWaitUntil, save);

struct SynchronizationCapabilities
{
    // Whether text document synchronization supports dynamic registration.
    optional<bool> dynamicRegistration;

    // The client supports sending will save notifications.
    optional<bool> willSave;

    // The client supports sending a will save request and
    // waits for a response providing text edits which will
    // be applied to the document before it is saved.
    optional<bool> willSaveWaitUntil;

    // The client supports did save notifications.
    optional<bool> didSave;

    MAKE_SWAP_METHOD(SynchronizationCapabilities, dynamicRegistration, willSave, willSaveWaitUntil, didSave);
};
MAKE_REFLECT_STRUCT(SynchronizationCapabilities, dynamicRegistration, willSave, willSaveWaitUntil, didSave);

struct CompletionItemKindCapabilities
{
    optional<std::vector<lsCompletionItemKind>> valueSet;
    MAKE_SWAP_METHOD(CompletionItemKindCapabilities, valueSet);
};
MAKE_REFLECT_STRUCT(CompletionItemKindCapabilities, valueSet);

struct CompletionItemCapabilities
{
    // Client supports snippets as insert text.
    //
    // A snippet can define tab stops and placeholders with `$1`, `$2`
    // and `${3:foo}`. `$0` defines the final tab stop, it defaults to
    // the end of the snippet. Placeholders with equal identifiers are linked,
    // that is typing in one will update others too.
    optional<bool> snippetSupport;

    // Client supports commit characters on a completion item.

    optional<bool> commitCharactersSupport;

    // Client supports the following content formats for the documentation
    // property. The order describes the preferred format of the client.

    optional<std::vector<std::string>> documentationFormat;

    // Client supports the deprecated property on a completion item.

    optional<bool> deprecatedSupport;

    //
    // Client supports the preselect property on a completion item.
    //
    optional<bool> preselectSupport;

    MAKE_SWAP_METHOD(
        CompletionItemCapabilities, snippetSupport, commitCharactersSupport, documentationFormat, deprecatedSupport,
        preselectSupport
    );
};
MAKE_REFLECT_STRUCT(
    CompletionItemCapabilities, snippetSupport, commitCharactersSupport, documentationFormat, deprecatedSupport,
    preselectSupport
);

//
// Capabilities specific to the `textDocument/completion`
//
struct CompletionCapabilities
{
    // Whether completion supports dynamic registration.
    optional<bool> dynamicRegistration;

    // The client supports the following `CompletionItem` specific
    // capabilities.
    optional<CompletionItemCapabilities> completionItem;

    //
    // The client supports the following `CompletionItemKind` specific
    // capabilities.
    //
    optional<CompletionItemKindCapabilities> completionItemKind;

    //
    // The client supports sending additional context information for a
    // `textDocument/completion` request.
    //
    optional<bool> contextSupport;

    MAKE_SWAP_METHOD(CompletionCapabilities, dynamicRegistration, completionItem, completionItemKind);
};

MAKE_REFLECT_STRUCT(CompletionCapabilities, dynamicRegistration, completionItem, completionItemKind);

struct HoverCapabilities : public DynamicRegistrationCapabilities
{
    //
    // Client supports the following content formats for the content
    // property. The order describes the preferred format of the client.
    //
    // See {@link MarkupKind} for allowed values.
    //
    optional<std::vector<std::string>> contentFormat;

    MAKE_SWAP_METHOD(HoverCapabilities, dynamicRegistration, contentFormat);
};
MAKE_REFLECT_STRUCT(HoverCapabilities, dynamicRegistration, contentFormat);

//
// Client capabilities specific to parameter information.
//
struct ParameterInformationCapabilities
{
    //
    // The client supports processing label offsets instead of a
    // simple label string.
    //
    // Since 3.14.0
    //
    optional<bool> labelOffsetSupport;

    MAKE_SWAP_METHOD(ParameterInformationCapabilities, labelOffsetSupport);
};
MAKE_REFLECT_STRUCT(ParameterInformationCapabilities, labelOffsetSupport)

struct SignatureInformationCapabilities
{
    //
    // Client supports the following content formats for the documentation
    // property. The order describes the preferred format of the client.
    //
    // See {@link MarkupKind} for allowed values.
    //
    std::vector<std::string> documentationFormat;

    //
    // Client capabilities specific to parameter information.
    //
    ParameterInformationCapabilities parameterInformation;

    MAKE_SWAP_METHOD(SignatureInformationCapabilities, documentationFormat, parameterInformation)
};
MAKE_REFLECT_STRUCT(SignatureInformationCapabilities, documentationFormat, parameterInformation)

struct SignatureHelpCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The client supports the following `SignatureInformation`
    // specific properties.
    //
    optional<SignatureInformationCapabilities> signatureInformation;

    MAKE_SWAP_METHOD(SignatureHelpCapabilities, dynamicRegistration, signatureInformation)
};
MAKE_REFLECT_STRUCT(SignatureHelpCapabilities, dynamicRegistration, signatureInformation)

struct DocumentSymbolCapabilities : public DynamicRegistrationCapabilities
{
    //
    // Specific capabilities for the `SymbolKind`.
    //
    optional<SymbolKindCapabilities> symbolKind;

    //
    // The client support hierarchical document symbols.
    //
    optional<bool> hierarchicalDocumentSymbolSupport;

    MAKE_SWAP_METHOD(DocumentSymbolCapabilities, dynamicRegistration, symbolKind, hierarchicalDocumentSymbolSupport)
};
MAKE_REFLECT_STRUCT(DocumentSymbolCapabilities, dynamicRegistration, symbolKind, hierarchicalDocumentSymbolSupport)

struct DeclarationCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The client supports additional metadata in the form of declaration links.
    //
    optional<bool> linkSupport;

    MAKE_SWAP_METHOD(DeclarationCapabilities, dynamicRegistration, linkSupport);
};
MAKE_REFLECT_STRUCT(DeclarationCapabilities, dynamicRegistration, linkSupport)

struct CodeActionKindCapabilities
{
    //
    // The code action kind values the client supports. When this
    // property exists the client also guarantees that it will
    // handle values outside its set gracefully and falls back
    // to a default value when unknown.
    //
    // See {@link CodeActionKind} for allowed values.
    //
    optional<std::vector<std::string>> valueSet;

    MAKE_SWAP_METHOD(CodeActionKindCapabilities, valueSet)
};
MAKE_REFLECT_STRUCT(CodeActionKindCapabilities, valueSet)

struct CodeActionLiteralSupportCapabilities
{
    optional<CodeActionKindCapabilities> codeActionKind;

    MAKE_SWAP_METHOD(CodeActionLiteralSupportCapabilities, codeActionKind)
};
MAKE_REFLECT_STRUCT(CodeActionLiteralSupportCapabilities, codeActionKind)

struct CodeActionCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The client support code action literals as a valid
    // response of the `textDocument/codeAction` request.
    //
    optional<CodeActionLiteralSupportCapabilities> codeActionLiteralSupport;

    MAKE_SWAP_METHOD(CodeActionCapabilities, dynamicRegistration, codeActionLiteralSupport)
};
MAKE_REFLECT_STRUCT(CodeActionCapabilities, dynamicRegistration, codeActionLiteralSupport)

struct RenameCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The client support code action literals as a valid
    // response of the `textDocument/codeAction` request.
    //
    optional<bool> prepareSupport;

    MAKE_SWAP_METHOD(RenameCapabilities, dynamicRegistration, prepareSupport)
};
MAKE_REFLECT_STRUCT(RenameCapabilities, dynamicRegistration, prepareSupport)

struct DiagnosticsTagSupport
{
    /**
         * The tags supported by the client.
         */
    std::vector<DiagnosticTag> valueSet;
    MAKE_SWAP_METHOD(DiagnosticsTagSupport, valueSet)
};
MAKE_REFLECT_STRUCT(DiagnosticsTagSupport, valueSet)

struct PublishDiagnosticsClientCapabilities : public DynamicRegistrationCapabilities
{
    /**
 * The client support code action literals as a valid
 * response of the `textDocument/codeAction` request.
 */
    optional<bool> relatedInformation;

    /**
         * Client supports the tag property to provide meta data about a diagnostic.
         * Clients supporting tags have to handle unknown tags gracefully.
         *
         * This property had been added and implemented as boolean before it was
         * added to the specification as {@link DiagnosticsTagSupport}. In order to
         * keep this implementation compatible with intermediate clients (including
         * vscode-language-client < 6.0.0) we add an either type here.
         *
         * Since 3.15
         */
    optional<std::pair<optional<bool>, optional<DiagnosticsTagSupport>>> tagSupport;

    /**
         * Whether the client interprets the version property of the
         * `textDocument/publishDiagnostics` notification's parameter.
         *
         * Since 3.15.0
         */
    optional<bool> versionSupport;

    /**
 * Client supports a codeDescription property
 *
 * @since 3.16.0
 */
    optional<bool> codeDescriptionSupport;

    /**
         * Whether code action supports the `data` property which is
         * preserved between a `textDocument/publishDiagnostics` and
         * `textDocument/codeAction` request.
         *
         * @since 3.16.0
         */
    optional<bool> dataSupport;

    MAKE_SWAP_METHOD(
        PublishDiagnosticsClientCapabilities, dynamicRegistration, relatedInformation, tagSupport, versionSupport,
        codeDescriptionSupport, dataSupport
    )
};
MAKE_REFLECT_STRUCT(
    PublishDiagnosticsClientCapabilities, dynamicRegistration, relatedInformation, tagSupport, versionSupport,
    codeDescriptionSupport, dataSupport
)

struct FoldingRangeCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
    // hint, servers are free to follow the limit.
    //
    optional<int> rangeLimit;

    //
    // If set, the client signals that it only supports folding complete lines. If set, client will
    // ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
    //
    optional<bool> lineFoldingOnly;
    MAKE_SWAP_METHOD(FoldingRangeCapabilities, dynamicRegistration, rangeLimit, lineFoldingOnly)
};
MAKE_REFLECT_STRUCT(FoldingRangeCapabilities, dynamicRegistration, rangeLimit, lineFoldingOnly)

struct SemanticHighlightingCapabilities : public DynamicRegistrationCapabilities
{
    //
    // The client support code action literals as a valid
    // response of the `textDocument/codeAction` request.
    //
    optional<bool> semanticHighlighting;

    MAKE_SWAP_METHOD(SemanticHighlightingCapabilities, dynamicRegistration, semanticHighlighting)
};
MAKE_REFLECT_STRUCT(SemanticHighlightingCapabilities, dynamicRegistration, semanticHighlighting)

struct SemanticTokensClientCapabilitiesRequestsFull
{

    //
    // The client will send the `textDocument/semanticTokens/full/delta` request if
    // the server provides a corresponding handler.
    //
    bool delta = false;
    MAKE_SWAP_METHOD(SemanticTokensClientCapabilitiesRequestsFull, delta)
};
MAKE_REFLECT_STRUCT(SemanticTokensClientCapabilitiesRequestsFull, delta)

struct SemanticTokensClientCapabilities : public DynamicRegistrationCapabilities
{
    //export  TokenFormat = 'relative';
    struct lsRequests
    {
        //
        // The client will send the `textDocument/semanticTokens/range` request
        // if the server provides a corresponding handler.
        //
        optional<std::pair<optional<bool>, optional<SemanticTokensClientCapabilitiesRequestsFull>>> range;
        //
        // The client will send the `textDocument/semanticTokens/full` request
        // if the server provides a corresponding handler.
        //
        optional<std::pair<optional<bool>, optional<lsp::Any>>> full;
        MAKE_SWAP_METHOD(lsRequests, range, full)
    };

    lsRequests requests;
    //
    // The token types that the client supports.
    //
    std::vector<std::string> tokenTypes;

    //
    // The token modifiers that the client supports.
    //
    std::vector<std::string> tokenModifiers;
    //
    // The formats the clients supports.
    //
    std::vector<std::string> formats;
    //
    // Whether the client supports tokens that can overlap each other.
    //
    optional<bool> overlappingTokenSupport;

    //
    // Whether the client supports tokens that can span multiple lines.
    //
    optional<bool> multilineTokenSupport;

    MAKE_SWAP_METHOD(
        SemanticTokensClientCapabilities, dynamicRegistration, requests, tokenTypes, tokenModifiers, formats,
        overlappingTokenSupport, multilineTokenSupport
    )
};
MAKE_REFLECT_STRUCT(SemanticTokensClientCapabilities::lsRequests, range, full)
MAKE_REFLECT_STRUCT(
    SemanticTokensClientCapabilities, dynamicRegistration, requests, tokenTypes, tokenModifiers, formats,
    overlappingTokenSupport, multilineTokenSupport
)

// Text document specific client capabilities.
struct lsTextDocumentClientCapabilities
{

    SynchronizationCapabilities synchronization;

    // Capabilities specific to the `textDocument/completion`
    optional<CompletionCapabilities> completion;

    // Capabilities specific to the `textDocument/hover`
    optional<HoverCapabilities> hover;

    // Capabilities specific to the `textDocument/signatureHelp`
    optional<SignatureHelpCapabilities> signatureHelp;

    // Capabilities specific to the `textDocument/references`
    optional<DynamicRegistrationCapabilities> references;

    // Capabilities specific to the `textDocument/documentHighlight`
    optional<DynamicRegistrationCapabilities> documentHighlight;

    // Capabilities specific to the `textDocument/documentSymbol`
    optional<DocumentSymbolCapabilities> documentSymbol;

    // Capabilities specific to the `textDocument/formatting`
    optional<DynamicRegistrationCapabilities> formatting;

    // Capabilities specific to the `textDocument/rangeFormatting`
    optional<DynamicRegistrationCapabilities> rangeFormatting;

    // Capabilities specific to the `textDocument/onTypeFormatting`
    optional<DynamicRegistrationCapabilities> onTypeFormatting;

    //
    // Capabilities specific to the `textDocument/declaration`
    //
    // Since 3.14.0
    //
    optional<DeclarationCapabilities> declaration;

    typedef DeclarationCapabilities DefinitionCapabilities;
    // Capabilities specific to the `textDocument/definition`
    optional<DefinitionCapabilities> definition;

    //
    // Capabilities specific to the `textDocument/typeDefinition`
    //
    // Since 3.6.0
    //
    typedef DeclarationCapabilities TypeDefinitionCapabilities;
    optional<TypeDefinitionCapabilities> typeDefinition;

    typedef DeclarationCapabilities ImplementationCapabilities;
    // Capabilities specific to the `textDocument/implementation`
    optional<ImplementationCapabilities> implementation;

    // Capabilities specific to the `textDocument/codeAction`
    optional<CodeActionCapabilities> codeAction;

    // Capabilities specific to the `textDocument/codeLens`
    optional<DynamicRegistrationCapabilities> codeLens;

    // Capabilities specific to the `textDocument/documentLink`
    optional<DynamicRegistrationCapabilities> documentLink;

    //
    // Capabilities specific to the `textDocument/documentColor` and the
    // `textDocument/colorPresentation` request.
    //
    // Since 3.6.0
    //
    optional<DynamicRegistrationCapabilities> colorProvider;

    // Capabilities specific to the `textDocument/rename`
    optional<RenameCapabilities> rename;

    //
    // Capabilities specific to `textDocument/publishDiagnostics`.
    //
    optional<PublishDiagnosticsClientCapabilities> publishDiagnostics;

    //
    // Capabilities specific to `textDocument/foldingRange` requests.
    //
    // Since 3.10.0
    //
    optional<FoldingRangeCapabilities> foldingRange;

    //
    // Capabilities specific to {@code textDocument/semanticHighlighting}.
    //
    optional<SemanticHighlightingCapabilities> semanticHighlightingCapabilities;

    //
    // Capabilities specific to {@code textDocument/typeHierarchy}.
    //
    optional<DynamicRegistrationCapabilities> typeHierarchyCapabilities;

    //
    // Capabilities specific to `textDocument/selectionRange` requests
    //

    optional<DynamicRegistrationCapabilities> selectionRange;

    //
    // Capabilities specific to the `textDocument/linkedEditingRange` request.
    //
    // @since 3.16.0
    //
    optional<DynamicRegistrationCapabilities> linkedEditingRange;

    //
    // Capabilities specific to the various call hierarchy requests.
    //
    // @since 3.16.0
    //
    optional<DynamicRegistrationCapabilities> callHierarchy;

    //
    // Capabilities specific to the various semantic token requests.
    //
    // @since 3.16.0
    //
    optional<SemanticTokensClientCapabilities> semanticTokens;

    //
    // Capabilities specific to the `textDocument/moniker` request.
    //
    // @since 3.16.0
    //
    optional<DynamicRegistrationCapabilities> moniker;

    //
    // Capabilities specific to the `textDocument/inlayHint` request.
    //
    // @since 3.17.0
    //
    optional<InlayHintClientCapabilities> inlayHint;

    MAKE_SWAP_METHOD(
        lsTextDocumentClientCapabilities, synchronization, completion, hover, signatureHelp, implementation, references,
        documentHighlight, documentSymbol, formatting, rangeFormatting, onTypeFormatting, declaration, definition,
        typeDefinition, implementation, codeAction, codeLens, documentLink, colorProvider, rename, publishDiagnostics,
        foldingRange, semanticHighlightingCapabilities, typeHierarchyCapabilities, callHierarchy, selectionRange,
        linkedEditingRange, semanticTokens, moniker, inlayHint
    )
};

MAKE_REFLECT_STRUCT(
    lsTextDocumentClientCapabilities, synchronization, completion, hover, signatureHelp, implementation, references,
    documentHighlight, documentSymbol, formatting, rangeFormatting, onTypeFormatting, declaration, definition,
    typeDefinition, implementation, codeAction, codeLens, documentLink, colorProvider, rename, publishDiagnostics,
    foldingRange, semanticHighlightingCapabilities, typeHierarchyCapabilities, callHierarchy, selectionRange,
    linkedEditingRange, semanticTokens, moniker, inlayHint
)
