#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 "InitializeParams.h"
#include "LibLsp/lsp/textDocument/SemanticTokens.h"

extern void Reflect(Reader&, std::pair<optional<lsTextDocumentSyncKind>, optional<lsTextDocumentSyncOptions>>&);

//
// Code Action options.
//
struct CodeActionOptions : WorkDoneProgressOptions
{
   //
   // CodeActionKinds that this server may return.
   //
   // The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
   // may list out every specific kind they provide.
   //
   typedef std::string CodeActionKind;
   std::vector<CodeActionKind> codeActionKinds;

   MAKE_SWAP_METHOD(CodeActionOptions, workDoneProgress, codeActionKinds);
};
MAKE_REFLECT_STRUCT(CodeActionOptions, workDoneProgress, codeActionKinds)
struct CodeLensOptions : WorkDoneProgressOptions
{
   //
   // Code lens has a resolve provider as well.
   //
   optional<bool> resolveProvider;
   MAKE_SWAP_METHOD(CodeLensOptions, workDoneProgress, resolveProvider);
};
MAKE_REFLECT_STRUCT(CodeLensOptions, workDoneProgress, resolveProvider)

// Format document on type options
struct lsDocumentOnTypeFormattingOptions : WorkDoneProgressOptions
{
   // A character on which formatting should be triggered, like `}`.
   std::string firstTriggerCharacter;

   // More trigger characters.
   std::vector<std::string> moreTriggerCharacter;
   MAKE_SWAP_METHOD(lsDocumentOnTypeFormattingOptions, workDoneProgress, firstTriggerCharacter, moreTriggerCharacter);
};
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, workDoneProgress, firstTriggerCharacter, moreTriggerCharacter);
struct RenameOptions : WorkDoneProgressOptions
{
   //
   // Renames should be checked and tested before being executed.
   //
   optional<bool> prepareProvider;
   MAKE_SWAP_METHOD(RenameOptions, workDoneProgress, prepareProvider);
};
MAKE_REFLECT_STRUCT(RenameOptions, workDoneProgress, prepareProvider)

struct DocumentFilter
{
   //
   // A language id, like `typescript`.
   //
   optional<std::string> language;
   //
   // A Uri [scheme](#Uri.scheme), like `file` or `untitled`.
   //
   optional<std::string> scheme;
   //
   // A glob pattern, like `*.{ts,js}`.
   //
   // Glob patterns can have the following syntax:
   // - `*` to match one or more characters in a path segment
   // - `?` to match on one character in a path segment
   // - `**` to match any number of path segments, including none
   // - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}
   //   matches all TypeScript and JavaScript files)
   // - `[]` to declare a range of characters to match in a path segment
   //   (e.g., `example.[0-9]` to match on `example.0`, `example.1`,...)
   // - `[!...]` to negate a range of characters to match in a path segment
   //   (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but
   //   not `example.0`)
   //
   optional<std::string> pattern;
   MAKE_SWAP_METHOD(DocumentFilter, language, scheme, pattern)
};
MAKE_REFLECT_STRUCT(DocumentFilter, language, scheme, pattern)

//A document selector is the combination of one or more document filters.
using DocumentSelector = std::vector<DocumentFilter>;

// Document link options
struct lsDocumentLinkOptions : WorkDoneProgressOptions
{
   // Document links have a resolve provider as well.
   optional<bool> resolveProvider;
   MAKE_SWAP_METHOD(lsDocumentLinkOptions, workDoneProgress, resolveProvider);
};
MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, workDoneProgress, resolveProvider);

// Execute command options.
struct lsExecuteCommandOptions : WorkDoneProgressOptions
{
   // The commands to be executed on the server
   std::vector<std::string> commands;
   MAKE_SWAP_METHOD(lsExecuteCommandOptions, workDoneProgress, commands);
};
MAKE_REFLECT_STRUCT(lsExecuteCommandOptions, workDoneProgress, commands);

struct TextDocumentRegistrationOptions
{
   //
   // A document selector to identify the scope of the registration. If set to null
   // the document selector provided on the client side will be used.
   //
   optional<DocumentSelector> documentSelector;

   MAKE_SWAP_METHOD(TextDocumentRegistrationOptions, documentSelector);
};
MAKE_REFLECT_STRUCT(TextDocumentRegistrationOptions, documentSelector);

//
// Static registration options to be returned in the initialize request.
//
struct StaticRegistrationOptions : public TextDocumentRegistrationOptions
{
   //
   // The id used to register the request. The id can be used to deregister
   // the request again. See also Registration#id.
   //
   optional<std::string> id;
   MAKE_SWAP_METHOD(StaticRegistrationOptions, documentSelector, id)
};
MAKE_REFLECT_STRUCT(StaticRegistrationOptions, documentSelector, id)

//
// The server supports workspace folder.
//
// Since 3.6.0
//

struct WorkspaceFoldersOptions
{
   //
   // The server has support for workspace folders
   //
   optional<bool> supported;

   //
   // Whether the server wants to receive workspace folder
   // change notifications.
   //
   // If a string is provided, the string is treated as an ID
   // under which the notification is registered on the client
   // side. The ID can be used to unregister for these events
   // using the `client/unregisterCapability` request.
   //
   optional<std::pair<optional<std::string>, optional<bool>>> changeNotifications;
   MAKE_SWAP_METHOD(WorkspaceFoldersOptions, supported, changeNotifications);
};
MAKE_REFLECT_STRUCT(WorkspaceFoldersOptions, supported, changeNotifications);

//
// A pattern kind describing if a glob pattern matches a file a folder or
// both.
//
// @since 3.16.0
//
enum lsFileOperationPatternKind
{
   file,
   folder
};
MAKE_REFLECT_TYPE_PROXY(lsFileOperationPatternKind)

//
// Matching options for the file operation pattern.
//
// @since 3.16.0
//
struct lsFileOperationPatternOptions
{

   //
   // The pattern should be matched ignoring casing.
   //
   optional<bool> ignoreCase;
   MAKE_SWAP_METHOD(lsFileOperationPatternOptions, ignoreCase)
};
MAKE_REFLECT_STRUCT(lsFileOperationPatternOptions, ignoreCase)
//
// A pattern to describe in which file operation requests or notifications
// the server is interested in.
//
// @since 3.16.0
//
struct lsFileOperationPattern
{
   //
   // The glob pattern to match. Glob patterns can have the following syntax:
   // - `*` to match one or more characters in a path segment
   // - `?` to match on one character in a path segment
   // - `**` to match any number of path segments, including none
   // - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}`
   //   matches all TypeScript and JavaScript files)
   // - `[]` to declare a range of characters to match in a path segment
   //   (e.g., `example.[0-9]` to match on `example.0`, `example.1`,...)
   // - `[!...]` to negate a range of characters to match in a path segment
   //   (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but
   //   not `example.0`)
   //
   std::string glob;

   //
   // Whether to match files or folders with this pattern.
   //
   // Matches both if undefined.
   //
   optional<lsFileOperationPatternKind> matches;

   //
   // Additional options used during matching.
   //
   optional<lsFileOperationPatternOptions> options;
   MAKE_SWAP_METHOD(lsFileOperationPattern, glob, matches, options)
};
MAKE_REFLECT_STRUCT(lsFileOperationPattern, glob, matches, options)
//
// A filter to describe in which file operation requests or notifications
// the server is interested in.
//
// @since 3.16.0
//
struct lsFileOperationFilter
{

   //
   // A Uri like `file` or `untitled`.
   //
   optional<std::string> scheme;

   //
   // The actual file operation pattern.
   //
   optional<lsFileOperationPattern> pattern;
   MAKE_SWAP_METHOD(lsFileOperationFilter, scheme, pattern)
};
MAKE_REFLECT_STRUCT(lsFileOperationFilter, scheme, pattern)
//
// The options to register for file operations.
//
// @since 3.16.0
//
struct lsFileOperationRegistrationOptions
{
   //
   // The actual filters.
   //
   optional<std::vector<lsFileOperationFilter>> filters;
   MAKE_SWAP_METHOD(lsFileOperationRegistrationOptions, filters)
};
MAKE_REFLECT_STRUCT(lsFileOperationRegistrationOptions, filters)

struct WorkspaceServerCapabilities
{
   //
   // The server supports workspace folder.
   //
   // Since 3.6.0
   //
   WorkspaceFoldersOptions workspaceFolders;

   //
   // The server is interested in file notifications/requests.
   //
   // @since 3.16.0
   //
   struct lsFileOperations
   {
       //
       // The server is interested in receiving didCreateFiles
       // notifications.
       //
       optional<lsFileOperationRegistrationOptions> didCreate;

       //
       // The server is interested in receiving willCreateFiles requests.
       //
       optional<lsFileOperationRegistrationOptions> willCreate;

       //
       // The server is interested in receiving didRenameFiles
       // notifications.
       //
       optional<lsFileOperationRegistrationOptions> didRename;

       //
       // The server is interested in receiving willRenameFiles requests.
       //
       optional<lsFileOperationRegistrationOptions> willRename;

       //
       // The server is interested in receiving didDeleteFiles file
       // notifications.
       //
       optional<lsFileOperationRegistrationOptions> didDelete;

       //
       // The server is interested in receiving willDeleteFiles file
       // requests.
       //
       optional<lsFileOperationRegistrationOptions> willDelete;
       MAKE_SWAP_METHOD(lsFileOperations, didCreate, willCreate, didRename, willRename, didDelete, willDelete)
   };
   optional<lsFileOperations> fileOperations;

   MAKE_SWAP_METHOD(WorkspaceServerCapabilities, workspaceFolders, fileOperations)
};
MAKE_REFLECT_STRUCT(WorkspaceServerCapabilities, workspaceFolders, fileOperations)
MAKE_REFLECT_STRUCT(
   WorkspaceServerCapabilities::lsFileOperations, didCreate, willCreate, didRename, willRename, didDelete, willDelete
)

//
// Semantic highlighting server capabilities.
//
// <p>
// <b>Note:</b> the <a href=
// "https://github.com/Microsoft/vscode-languageserver-node/pull/367">{@code textDocument/semanticHighlighting}
// language feature</a> is not yet part of the official LSP specification.
//

struct SemanticHighlightingServerCapabilities
{
   //
   // A "lookup table" of semantic highlighting <a href="https://manual.macromates.com/en/language_grammars">TextMate scopes</a>
   // supported by the language server. If not defined or empty, then the server does not support the semantic highlighting
   // feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from
   // the server.
   //
   std::vector<std::vector<std::string>> scopes;
   MAKE_SWAP_METHOD(SemanticHighlightingServerCapabilities, scopes)
};
MAKE_REFLECT_STRUCT(SemanticHighlightingServerCapabilities, scopes)

struct SemanticTokensServerFull
{
   //
   // The server supports deltas for full documents.
   //
   bool delta = false;
   MAKE_SWAP_METHOD(SemanticTokensServerFull, delta)
};
MAKE_REFLECT_STRUCT(SemanticTokensServerFull, delta)
struct SemanticTokensWithRegistrationOptions
{
   SemanticTokensLegend legend;

   //
   // Server supports providing semantic tokens for a specific range
   // of a document.
   //
   optional<std::pair<optional<bool>, optional<lsp::Any>>> range;

   //
   // Server supports providing semantic tokens for a full document.
   //
   optional<std::pair<optional<bool>, optional<SemanticTokensServerFull>>> full;

   //
   // A document selector to identify the scope of the registration. If set to null
   // the document selector provided on the client side will be used.
   //
   optional<std::vector<DocumentFilter>> documentSelector;
   //
   // The id used to register the request. The id can be used to deregister
   // the request again. See also Registration#id.
   //
   optional<std::string> id;
   MAKE_SWAP_METHOD(SemanticTokensWithRegistrationOptions, legend, range, full, documentSelector, id)
};
MAKE_REFLECT_STRUCT(SemanticTokensWithRegistrationOptions, legend, range, full, documentSelector, id)

using DocumentColorOptions = WorkDoneProgressOptions;
using FoldingRangeOptions = WorkDoneProgressOptions;

struct InlayHintOptions : WorkDoneProgressOptions
{

   /**
    * The server provides support to resolve additional
    * information for an inlay hint item.
    */
   optional<bool> resolveProvider;

   MAKE_SWAP_METHOD(InlayHintOptions, workDoneProgress, resolveProvider);
};

MAKE_REFLECT_STRUCT(InlayHintOptions, workDoneProgress, resolveProvider)

struct lsServerCapabilities
{
   // Defines how text documents are synced. Is either a detailed structure
   // defining each notification or for backwards compatibility the

   // TextDocumentSyncKind number.
   optional<std::pair<optional<lsTextDocumentSyncKind>, optional<lsTextDocumentSyncOptions>>> textDocumentSync;

   // The server provides hover support.
   optional<bool> hoverProvider;

   // The server provides completion support.
   optional<lsCompletionOptions> completionProvider;

   // The server provides signature help support.
   optional<lsSignatureHelpOptions> signatureHelpProvider;

   // The server provides goto definition support.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> definitionProvider;

   //
   // The server provides Goto Type Definition support.
   //
   // Since 3.6.0
   //
   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> typeDefinitionProvider;

   // The server provides implementation support.
   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> implementationProvider;

   // The server provides find references support.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> referencesProvider;

   // The server provides document highlight support.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> documentHighlightProvider;

   // The server provides document symbol support.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> documentSymbolProvider;

   // The server provides workspace symbol support.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> workspaceSymbolProvider;

   // The server provides code actions.
   optional<std::pair<optional<bool>, optional<CodeActionOptions>>> codeActionProvider;

   // The server provides code lens.
   optional<CodeLensOptions> codeLensProvider;

   // The server provides document formatting.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> documentFormattingProvider;

   // The server provides document range formatting.
   optional<std::pair<optional<bool>, optional<WorkDoneProgressOptions>>> documentRangeFormattingProvider;

   // The server provides document formatting on typing.
   optional<lsDocumentOnTypeFormattingOptions> documentOnTypeFormattingProvider;

   // The server provides rename support.
   optional<std::pair<optional<bool>, optional<RenameOptions>>> renameProvider;

   // The server provides document link support.
   optional<lsDocumentLinkOptions> documentLinkProvider;

   //
   // The server provides color provider support.
   //
   // @since 3.6.0
   //
   optional<std::pair<optional<bool>, optional<DocumentColorOptions>>> colorProvider;

   //
   // The server provides folding provider support.
   //
   // @since 3.10.0
   //
   optional<std::pair<optional<bool>, optional<FoldingRangeOptions>>> foldingRangeProvider;

   // The server provides execute command support.
   optional<lsExecuteCommandOptions> executeCommandProvider;

   //
   // Workspace specific server capabilities
   //
   optional<WorkspaceServerCapabilities> workspace;

   //
   // Semantic highlighting server capabilities.
   //

   optional<SemanticHighlightingServerCapabilities> semanticHighlighting;

   //
   // Server capability for calculating super- and subtype hierarchies.
   // The LS supports the type hierarchy language feature, if this capability is set to {@code true}.
   //
   // <p>
   // <b>Note:</b> the <a href=
   // "https://github.com/Microsoft/vscode-languageserver-node/pull/426">{@code textDocument/typeHierarchy}
   // language feature</a> is not yet part of the official LSP specification.
   //

   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> typeHierarchyProvider;

   //
   // The server provides Call Hierarchy support.
   //

   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> callHierarchyProvider;

   //
   // The server provides selection range support.
   //
   // Since 3.15.0
   //
   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> selectionRangeProvider;

   //
   // The server provides linked editing range support.
   //
   // Since 3.16.0
   //
   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> linkedEditingRangeProvider;

   //
   // The server provides semantic tokens support.
   //
   // Since 3.16.0
   //
   optional<SemanticTokensWithRegistrationOptions> semanticTokensProvider;

   //
   // Whether server provides moniker support.
   //
   // Since 3.16.0
   //
   optional<std::pair<optional<bool>, optional<StaticRegistrationOptions>>> monikerProvider;

   /**
       * The server provides inlay hints.
       *
       * @since 3.17.0
       */
   optional<std::pair<optional<bool>, optional<InlayHintOptions>>> inlayHintProvider;

   optional<lsp::Any> experimental;

   MAKE_SWAP_METHOD(
       lsServerCapabilities, textDocumentSync, hoverProvider, completionProvider, signatureHelpProvider,
       definitionProvider, typeDefinitionProvider, implementationProvider, referencesProvider,
       documentHighlightProvider, documentSymbolProvider, workspaceSymbolProvider, codeActionProvider,
       codeLensProvider, documentFormattingProvider, documentRangeFormattingProvider, documentOnTypeFormattingProvider,
       renameProvider, documentLinkProvider, executeCommandProvider, workspace, semanticHighlighting,
       typeHierarchyProvider, callHierarchyProvider, selectionRangeProvider, experimental, colorProvider,
       foldingRangeProvider, linkedEditingRangeProvider, monikerProvider, semanticTokensProvider
   )
};
MAKE_REFLECT_STRUCT(
   lsServerCapabilities, textDocumentSync, hoverProvider, completionProvider, signatureHelpProvider,
   definitionProvider, typeDefinitionProvider, implementationProvider, referencesProvider, documentHighlightProvider,
   documentSymbolProvider, workspaceSymbolProvider, codeActionProvider, codeLensProvider, documentFormattingProvider,
   documentRangeFormattingProvider, documentOnTypeFormattingProvider, renameProvider, documentLinkProvider,
   executeCommandProvider, workspace, semanticHighlighting, typeHierarchyProvider, callHierarchyProvider,
   selectionRangeProvider, experimental, colorProvider, foldingRangeProvider, linkedEditingRangeProvider,
   monikerProvider, semanticTokensProvider
)