"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vscode_languageserver_1 = require("vscode-languageserver");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const browser_1 = require("vscode-languageserver/browser");
const flinkdb_schema_json_1 = __importDefault(require("./assets/flinkdb.schema.json"));
const constants_1 = require("./constants");
const execute_command_1 = require("./execute-command");
const lsp_server_1 = require("./lsp-server");
const protocol_translation_1 = require("./protocol-translation");
const messageReader = new browser_1.BrowserMessageReader(self);
const messageWriter = new browser_1.BrowserMessageWriter(self);
const connection = (0, browser_1.createConnection)(messageReader, messageWriter);
connection.onInitialize(() => {
    const capabilities = {
        textDocumentSync: vscode_languageserver_1.TextDocumentSyncKind.Incremental,
        executeCommandProvider: {
            commands: [
                constants_1.EXTRACT_SQL_STRUCTURE_COMMAND,
                constants_1.REGISTER_SCHEMAS_COMMAND,
                constants_1.PREVIEW_SCRIPT_COMMAND,
                constants_1.EXTRACT_SCHEMA_CONTEXTS_COMMAND,
                constants_1.COLLECT_TOKENS_COMMAND,
                constants_1.COLUMN_LEVEL_LINEAGE_COMMAND
            ]
        },
        documentFormattingProvider: true,
        referencesProvider: true,
        hoverProvider: true,
        foldingRangeProvider: true,
        renameProvider: true,
        codeActionProvider: true,
        completionProvider: {
            triggerCharacters: '.1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
            resolveProvider: true
        }
    };
    return { capabilities };
});
const documents = new vscode_languageserver_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
const lspServer = new lsp_server_1.LSPServer();
documents.listen(connection);
documents.onDidClose(e => {
    lspServer.warehouse.removeParsingValue(e.document.uri);
});
documents.onDidChangeContent(change => {
    if (!lspServer.warehouse.hasParsingValue(change.document)) {
        lspServer.warehouse.setParsingValue(change.document);
    }
    else {
        const parseValueCache = lspServer.warehouse.getParsingValue(change.document);
        if (change.document.getText() === parseValueCache.origin) {
            return;
        }
        lspServer.warehouse.setParsingValue(change.document);
    }
});
connection.onDidChangeWatchedFiles(() => {
});
connection.onRequest(vscode_languageserver_1.DocumentDiagnosticRequest.type, params => {
    const textDocument = documents.get(params.textDocument.uri);
    if (!textDocument) {
        console.error('Language Server: TextDocument not found.');
        return { kind: 'full', items: [] };
    }
    const items = lspServer.doValidation(textDocument);
    return { kind: 'full', items };
});
connection.onCompletion((params) => {
    const { textDocument, position } = params;
    const document = documents.get(textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return [];
    }
    return lspServer.doCompletion(document, position).completionItems;
});
connection.onCompletionResolve((item) => {
    if (!item.detail) {
        item.detail = 'reserved keyword';
    }
    return item;
});
connection.onCodeAction((params) => {
    const actions = [];
    const diagnostics = params.context.diagnostics;
    if (!diagnostics.length) {
        return [];
    }
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return [];
    }
    const kinds = params.context.only;
    if (kinds?.includes(vscode_languageserver_1.CodeActionKind.QuickFix)) {
        diagnostics.forEach(diagnostic => {
            const quickFixes = diagnostic.data?.suggestions
                .filter((s) => s !== 'EOF')
                .map((newText) => ({
                title: `Cannot find name '${document.getText(diagnostic.range)}'. Do you mean '${newText}'?`,
                kind: vscode_languageserver_1.CodeActionKind.QuickFix,
                diagnostics: [diagnostic],
                edit: {
                    changes: {
                        [params.textDocument.uri]: [
                            {
                                newText,
                                range: diagnostic.range
                            }
                        ]
                    }
                }
            })) || [];
            actions.push(...quickFixes);
        });
    }
    return actions;
});
connection.onDocumentFormatting((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return [];
    }
    return lspServer.doFormatting(document, params.options);
});
connection.onReferences((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return [];
    }
    const semanticToken = lspServer
        .collectTokens(document)
        .semanticTokens.find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range));
    if (!semanticToken) {
        return [];
    }
    let references = lspServer.doReferences(document, params.position).map(reference => {
        return {
            uri: document.uri,
            range: reference
        };
    });
    documents
        .all()
        .filter(doc => doc.uri !== params.textDocument.uri)
        .forEach(doc => {
        const semanticTokens = lspServer.collectTokens(doc).semanticTokens;
        references = references.concat(semanticTokens
            .filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken))
            .map(t => ({ uri: doc.uri, range: t.range })));
    });
    return references;
});
connection.onHover((params) => {
    const document = documents.get(params.textDocument.uri);
    const contents = [];
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return { contents };
    }
    const token = lspServer.getTokenByPosition(document, params.position);
    if (token?.text === undefined) {
        return { contents };
    }
    const functionItem = flinkdb_schema_json_1.default.functions.find(f => token.text.localeCompare(f.name, undefined, { sensitivity: 'accent' }) === 0);
    if (functionItem) {
        contents.push(`**System (Built-in) Function**`);
        contents.push(functionItem.description);
        contents.push(`For more information, please refer to [Flink Document](https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/dev/table/functions/systemfunctions/).`);
    }
    return {
        contents
    };
});
connection.onFoldingRanges((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return [];
    }
    return lspServer.doFoldingRanges(document);
});
connection.onRenameRequest((params) => {
    const document = documents.get(params.textDocument.uri);
    if (!document) {
        console.error('Language Server: TextDocument not found.');
        return;
    }
    const semanticToken = lspServer
        .collectTokens(document)
        .semanticTokens.find(t => (0, protocol_translation_1.positionInRange)(document, params.position, t.range));
    if (!semanticToken) {
        return;
    }
    const workspaceEdit = { changes: {} };
    documents.all().forEach(doc => {
        const tokens = lspServer.collectTokens(doc).semanticTokens.filter(t => (0, lsp_server_1.isSemanticTokenReference)(t, semanticToken));
        workspaceEdit.changes[doc.uri] = tokens.map(t => ({
            newText: params.newName,
            range: t.range
        }));
    });
    return workspaceEdit;
});
connection.onExecuteCommand(params => (0, execute_command_1.handleExecuteCommand)(documents, lspServer, params));
connection.listen();
