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

namespace lsp::protocol
{
    enum class NotebookCellKind
    {
        Markup = 1,
        Code = 2,
    };

    struct ExecutionSummary
    {
        uinteger executionOrder;
        std::optional<boolean> success;
    };

    struct NotebookCell
    {
        NotebookCellKind kind;
        DocumentUri document;
        std::optional<LSPObject> metadata;
        std::optional<ExecutionSummary> executionSummary;
    };

    struct NotebookDocument
    {
        URI uri;
        string notebookType;
        integer version;
        LSPObject metadata;
        std::vector<NotebookCell> cells;
    };

    struct NotebookDocumentFilter
    {
        string notebookType;
        std::optional<string> scheme;
        std::optional<string> pattern;
    };

    struct NotebookCellTextDocumentFilter
    {
        std::variant<string, NotebookDocumentFilter> notebook;
        std::optional<string> language;
    };

    struct NotebookSelector
    {
        struct Cell
        {
            string language;
        };

        std::variant<string, NotebookDocumentFilter> notebook;
        std::optional<std::vector<Cell>> cells;
    };

    struct NotebookDocumentSyncOptions
    {
        std::vector<NotebookSelector> notebookSelector;
        std::optional<boolean> save;
    };

    struct NotebookDocumentSyncRegistrationOptions : NotebookDocumentSyncOptions, StaticRegistrationOptions
    {
    };

    struct NotebookDocumentSyncClientCapabilities
    {
        std::optional<boolean> dynamicRegistration;
        std::optional<boolean> executionSummarySupport;
    };

    struct NotebookDocumentClientCapabilities
    {
        NotebookDocumentSyncClientCapabilities synchronization;
    };

    struct DidOpenNotebookDocumentParams
    {
        NotebookDocument notebookDocument;
        std::vector<TextDocumentItem> cellTextDocuments;
    };

    struct VersionedNotebookDocumentIdentifier
    {
        integer version;
        URI uri;
    };

    struct NotebookCellArrayChange
    {
        uinteger start;
        uinteger deleteCount;
        std::optional<std::vector<NotebookCell>> cells;
    };

    struct NotebookDocumentChangeEvent
    {
        struct Cell
        {
            struct Structure
            {
                NotebookCellArrayChange array;
                std::optional<std::vector<TextDocumentItem>> didOpen;
                std::optional<std::vector<TextDocumentIdentifier>> didClose;
            };

            struct TextContent
            {
                VersionedTextDocumentIdentifier document;
                std::vector<TextDocumentContentChangeEvent> changes;
            };

            std::optional<Structure> structure;
            std::optional<std::vector<NotebookCell>> data;
            std::optional<TextContent> textContent;
        };

        std::optional<LSPObject> metadata;
        std::optional<std::vector<Cell>> cells;
    };

    struct DidChangeNotebookDocumentParams
    {
        VersionedNotebookDocumentIdentifier notebookDocument;
        NotebookDocumentChangeEvent change;
    };

    struct NotebookDocumentIdentifier
    {
        URI uri;
    };

    struct DidSaveNotebookDocumentParams
    {
        NotebookDocumentIdentifier notebookDocument;
    };

    struct DidCloseNotebookDocumentParams
    {
        NotebookDocumentIdentifier notebookDocument;
        std::vector<TextDocumentIdentifier> cellTextDocuments;
    };

}
