#pragma once
#include "./basic_types.hpp"
#include "./document_sync.hpp"
#include "./diagnostics.hpp"
#include "registration.hpp"

namespace lsp::protocol
{
    struct CreateFileOptions
    {
        boolean overwrite;
        boolean ignoreIfExists;
    };

    struct CreateFile
    {
        string kind = "create";
        DocumentUri uri;
        std::optional<CreateFileOptions> options;
        std::optional<string> annotationId;
    };

    struct RenameFileOptions
    {
        boolean overwrite;
        boolean ignoreIfExists;
    };

    struct RenameFile
    {
        string kind = "rename";
        DocumentUri oldUri;
        DocumentUri newUri;
        std::optional<RenameFileOptions> options;
        std::optional<string> annotationId;
    };

    struct DeleteFileOptions
    {
        boolean recursive;
        boolean ignoreIfNotExists;
    };

    struct DeleteFile
    {
        string kind = "delete";
        DocumentUri uri;
        std::optional<DeleteFileOptions> options;
        std::optional<string> annotationId;
    };

    struct WorkspaceEdit
    {
        std::map<DocumentUri, std::vector<TextEdit>> changes;
        std::variant<std::vector<TextDocumentEdit>, std::vector<CreateFile>, std::vector<RenameFile>, std::vector<DeleteFile>> documentChanges;
        std::optional<std::map<string, ChangeAnnotation>> changeAnnotations;
    };

    using ResourceOperationKind = std::string_view;
    namespace ResourceOperationKindLiterals
    {
        inline constexpr ResourceOperationKind Create = "create";
        inline constexpr ResourceOperationKind Rename = "rename";
        inline constexpr ResourceOperationKind Delete = "delete";
    }

    using FailureHandlingKind = std::string_view;
    namespace FailureHandlingKindLiterals
    {
        inline constexpr FailureHandlingKind Abort = "abort";
        inline constexpr FailureHandlingKind Transactional = "transactional";
        inline constexpr FailureHandlingKind TextOnlyTransactional = "textOnlyTransactional";
        inline constexpr FailureHandlingKind Undo = "undo";
        inline constexpr FailureHandlingKind Commit = "commit";
    }

    struct WorkspaceEditClientCapabilities
    {
        struct ChangeAnnotationSupport
        {
            std::optional<bool> groupsOnLabel;
        };

        boolean documentChanges;
        std::optional<std::vector<ResourceOperationKind>> resourceOperations;
        std::optional<FailureHandlingKind> failureHandling;
        std::optional<boolean> normalizesLineEndings;
        ChangeAnnotationSupport changeAnnotationSupport;
        std::optional<boolean> metadataSupport;
        std::optional<boolean> snippetEditSupport;
    };

    struct WorkspaceFolder
    {
        URI uri;
        string name;
    };

    struct WorkspaceFolderServerCapabilities
    {
        std::optional<boolean> supported;
        std::optional<std::variant<string, boolean>> changeNotifications;
    };

    struct WorkspaceFoldersChangeEvent
    {
        std::vector<WorkspaceFolder> added;
        std::vector<WorkspaceFolder> removed;
    };

    struct WorkspaceEditMetadata
    {
        std::optional<boolean> isRefactoring;
    };

    struct ApplyWorkspaceEditParams
    {
        std::optional<string> label;
        WorkspaceEdit edit;
        std::optional<WorkspaceEditMetadata> metadata;
    };

    struct ApplyWorkspaceEditResult
    {
        boolean applied;
        std::optional<string> failureReason;
        std::optional<std::vector<Diagnostic>> failedChanges;
    };

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

    struct TextDocumentContentOptions
    {
        std::vector<string> schemes;
    };

    struct TextDocumentContentRegistrationOptions : TextDocumentContentOptions, StaticRegistrationOptions
    {
    };

    struct TextDocumentContentParams
    {
        DocumentUri uri;
    };

    struct TextDocumentContentResult
    {
        string text;
    };

    struct TextDocumentContentRefreshParams
    {
        DocumentUri uri;
    };
}
