"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_1 = require("vscode-languageserver/node");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const language_support_1 = require("@neo4j-cypher/language-support");
const query_tools_1 = require("@neo4j-cypher/query-tools");
const autocompletion_1 = require("./autocompletion");
const formatting_1 = require("./formatting");
const linting_1 = require("./linting");
const signatureHelp_1 = require("./signatureHelp");
const syntaxColouring_1 = require("./syntaxColouring");
const workerpool_1 = __importDefault(require("workerpool"));
const path_1 = require("path");
class SymbolFetcher {
    processing = false;
    nextJob;
    defaultWorkerPath = (0, path_1.join)(__dirname, 'lintWorker.cjs');
    symbolTablePool = workerpool_1.default.pool(this.defaultWorkerPath, {
        maxWorkers: 1,
        workerTerminateTimeout: 0,
    });
    queueSymbolJob(query, uri, schema) {
        this.nextJob = { query, uri, schema };
        if (!this.processing) {
            void this.processJobQueue();
        }
    }
    async processJobQueue() {
        this.processing = true;
        const proxyWorker = (await this.symbolTablePool.proxy());
        while (this.nextJob) {
            try {
                const query = this.nextJob.query;
                const dbSchema = this.nextJob.schema;
                const docUri = this.nextJob.uri;
                this.nextJob = undefined;
                const result = await proxyWorker.lintCypherQuery(query, dbSchema);
                if (
                //if this.nextJob has new doc, our result is no longer valid
                result.symbolTables &&
                    !(this.nextJob && this.nextJob.uri != docUri)) {
                    language_support_1.parserWrapper.setSymbolsInfo({
                        query,
                        symbolTables: result.symbolTables,
                    }, async (symbolTables) => await connection.sendNotification('symbolTableDone', {
                        symbolTables,
                    }));
                }
            }
            catch (e) {
                //eslint-disable-next-line
                console.log('Symbol table calculation failed');
            }
        }
        this.processing = false;
    }
}
const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
let settings = undefined;
// Create a simple text document manager.
const documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
const neo4jSchemaPoller = new query_tools_1.Neo4jSchemaPoller();
const symbolFetcher = new SymbolFetcher();
async function lintSingleDocument(document) {
    symbolFetcher.queueSymbolJob(document.getText(), document.uri, neo4jSchemaPoller?.metadata?.dbSchema);
    if (settings?.features?.linting) {
        return (0, linting_1.lintDocument)(document, (diagnostics) => {
            void connection.sendDiagnostics({
                uri: document.uri,
                diagnostics,
            });
        }, async (symbolTables) => await connection.sendNotification('symbolTableDone', {
            symbolTables: symbolTables,
        }), neo4jSchemaPoller);
    }
    else {
        void connection.sendDiagnostics({
            uri: document.uri,
            diagnostics: [],
        });
    }
}
function relintAllDocuments() {
    void documents.all().map(lintSingleDocument);
}
connection.onInitialize(() => {
    const result = {
        capabilities: {
            textDocumentSync: node_1.TextDocumentSyncKind.Full,
            // Tell the client what features does the server support
            completionProvider: {
                resolveProvider: false,
                triggerCharacters: ['.', ':', '{', '$', ')', ' '],
            },
            semanticTokensProvider: {
                documentSelector: [{ language: 'cypher' }],
                legend: language_support_1.syntaxColouringLegend,
                range: false,
                full: {
                    delta: false,
                },
            },
            signatureHelpProvider: {
                triggerCharacters: ['(', ',', ')'],
            },
            documentFormattingProvider: true,
        },
    };
    return result;
});
connection.onInitialized(() => {
    void connection.client.register(node_1.DidChangeConfigurationNotification.type, {
        section: 'neo4j',
    });
    const registrationOptions = {
        documentSelector: [{ language: 'cypher' }],
        legend: language_support_1.syntaxColouringLegend,
        range: false,
        full: {
            delta: false,
        },
    };
    void connection.client.register(node_1.SemanticTokensRegistrationType.type, registrationOptions);
});
connection.onDidChangeConfiguration((params) => {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
    settings = params.settings?.neo4j;
    relintAllDocuments();
});
documents.onDidChangeContent((change) => lintSingleDocument(change.document));
// Trigger the syntax colouring
connection.languages.semanticTokens.on((0, syntaxColouring_1.applySyntaxColouringForDocument)(documents));
// Trigger the signature help, providing info about functions / procedures
connection.onSignatureHelp((0, signatureHelp_1.doSignatureHelp)(documents, neo4jSchemaPoller));
// Trigger the auto completion
connection.onCompletion((0, autocompletion_1.doAutoCompletion)(documents, neo4jSchemaPoller));
connection.onNotification('updateLintWorker', (linterSettings) => {
    const lintWorkerPath = linterSettings.lintWorkerPath;
    const linterVersion = linterSettings.linterVersion;
    void (async () => {
        await (0, linting_1.setLintWorker)(lintWorkerPath, linterVersion);
        relintAllDocuments();
    })();
});
connection.onNotification('connectionUpdated', (connectionSettings) => {
    changeConnection(connectionSettings);
    neo4jSchemaPoller.events.once('schemaFetched', relintAllDocuments);
});
connection.onNotification('fetchSymbolTable', (params) => {
    neo4jSchemaPoller.events.once('schemaFetched', void symbolFetcher.queueSymbolJob(params.query, params.uri, params.schema));
});
connection.onNotification('updateParameters', (parameters) => {
    neo4jSchemaPoller.setParameters(parameters);
    relintAllDocuments();
});
connection.onDocumentFormatting((params) => {
    return (0, formatting_1.formatDocument)(params, documents);
});
connection.onNotification('connectionDisconnected', () => {
    disconnect();
    relintAllDocuments();
});
documents.listen(connection);
connection.listen();
connection.onExit(() => {
    void (0, linting_1.cleanupWorkers)();
});
const changeConnection = (connectionSettings) => {
    disconnect();
    if (neo4jSchemaPoller.connection === undefined &&
        connectionSettings.connect &&
        connectionSettings.password &&
        connectionSettings.connectURL &&
        connectionSettings.user) {
        void neo4jSchemaPoller.persistentConnect(connectionSettings.connectURL, {
            username: connectionSettings.user,
            password: connectionSettings.password,
        }, { appName: 'cypher-language-server' }, connectionSettings.database);
    }
};
const disconnect = () => {
    neo4jSchemaPoller.disconnect();
};
//# sourceMappingURL=server.js.map