"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sleep = exports.createWorkspaces = void 0;
const vscode = require("vscode-languageserver");
const types_1 = require("../types");
const workspace_1 = require("./workspace");
const isFileInDir_1 = require("./utils/isFileInDir");
function createWorkspaces(context) {
    const { uriToFileName } = context.server.runtimeEnv;
    const workspaces = new Map();
    let semanticTokensReq = 0;
    let documentUpdatedReq = 0;
    context.workspaces.documents.onDidChangeContent(({ textDocument }) => {
        updateDiagnostics(textDocument.uri);
    });
    context.workspaces.documents.onDidClose(({ textDocument }) => {
        context.server.connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
    });
    context.server.onDidChangeWatchedFiles(({ changes }) => {
        const tsConfigChanges = changes.filter(change => workspace_1.rootTsConfigNames.includes(change.uri.substring(change.uri.lastIndexOf('/') + 1)));
        if (tsConfigChanges.length) {
            reloadDiagnostics();
        }
        else {
            updateDiagnosticsAndSemanticTokens();
        }
    });
    context.server.configurationHost?.onDidChangeConfiguration?.(updateDiagnosticsAndSemanticTokens);
    return {
        workspaces,
        getProject: getProjectAndTsConfig,
        reloadProject,
        add: (rootUri) => {
            if (!workspaces.has(rootUri.toString())) {
                workspaces.set(rootUri.toString(), (0, workspace_1.createWorkspace)({
                    ...context,
                    workspace: {
                        rootUri,
                    },
                }));
            }
        },
        remove: (rootUri) => {
            const _workspace = workspaces.get(rootUri.toString());
            workspaces.delete(rootUri.toString());
            (async () => {
                (await _workspace)?.dispose();
            })();
        },
    };
    async function reloadProject() {
        for (const [_, workspace] of workspaces) {
            (await workspace).reload();
        }
        reloadDiagnostics();
    }
    function reloadDiagnostics() {
        for (const doc of context.workspaces.documents.data.values()) {
            context.server.connection.sendDiagnostics({ uri: doc.uri, diagnostics: [] });
        }
        updateDiagnosticsAndSemanticTokens();
    }
    async function updateDiagnosticsAndSemanticTokens() {
        const req = ++semanticTokensReq;
        await updateDiagnostics();
        const delay = 250;
        await sleep(delay);
        if (req === semanticTokensReq) {
            if (context.workspaces.initParams.capabilities.textDocument?.semanticTokens) {
                context.server.connection.languages.semanticTokens.refresh();
            }
            if (context.workspaces.initParams.capabilities.textDocument?.inlayHint) {
                context.server.connection.languages.inlayHint.refresh();
            }
        }
    }
    async function updateDiagnostics(docUri) {
        if ((context.workspaces.initOptions.diagnosticModel ?? types_1.DiagnosticModel.Push) !== types_1.DiagnosticModel.Push)
            return;
        const req = ++documentUpdatedReq;
        const delay = 250;
        const cancel = context.workspaces.cancelTokenHost.createCancellationToken({
            get isCancellationRequested() {
                return req !== documentUpdatedReq;
            },
            onCancellationRequested: vscode.Event.None,
        });
        const changeDoc = docUri ? context.workspaces.documents.data.uriGet(docUri) : undefined;
        const otherDocs = [...context.workspaces.documents.data.values()].filter(doc => doc !== changeDoc);
        if (changeDoc) {
            await sleep(delay);
            if (cancel.isCancellationRequested) {
                return;
            }
            await sendDocumentDiagnostics(changeDoc.uri, changeDoc.version, cancel);
        }
        for (const doc of otherDocs) {
            await sleep(delay);
            if (cancel.isCancellationRequested) {
                break;
            }
            await sendDocumentDiagnostics(doc.uri, doc.version, cancel);
        }
    }
    async function sendDocumentDiagnostics(uri, version, cancel) {
        const project = (await getProjectAndTsConfig(uri))?.project;
        if (!project)
            return;
        // fix https://github.com/vuejs/language-tools/issues/2627
        if (context.workspaces.initOptions.serverMode === types_1.ServerMode.Syntactic) {
            return;
        }
        // const mode = context.initOptions.serverMode === ServerMode.PartialSemantic ? 'semantic' as const
        // 	: context.initOptions.serverMode === ServerMode.Syntactic ? 'syntactic' as const
        // 		: 'all' as const;
        const languageService = project.getLanguageService();
        const errors = await languageService.doValidation(uri, 'all', cancel, result => {
            context.server.connection.sendDiagnostics({ uri: uri, diagnostics: result, version });
        });
        context.server.connection.sendDiagnostics({ uri: uri, diagnostics: errors, version });
    }
    async function getProjectAndTsConfig(uri) {
        let rootUris = [...workspaces.keys()]
            .filter(rootUri => (0, isFileInDir_1.isFileInDir)(uriToFileName(uri), uriToFileName(rootUri)))
            .sort((a, b) => (0, workspace_1.sortTsConfigs)(uriToFileName(uri), uriToFileName(a), uriToFileName(b)));
        if (context.workspaces.initOptions.serverMode !== types_1.ServerMode.Syntactic) {
            for (const rootUri of rootUris) {
                const workspace = await workspaces.get(rootUri);
                const projectAndTsConfig = await workspace?.getProjectAndTsConfig(uri);
                if (projectAndTsConfig) {
                    return projectAndTsConfig;
                }
            }
        }
        if (!rootUris.length) {
            rootUris = [...workspaces.keys()];
        }
        if (rootUris.length) {
            const project = await (await workspaces.get(rootUris[0]))?.getInferredProject();
            project?.tryAddFile(uriToFileName(uri));
            return {
                tsconfig: undefined,
                project,
            };
        }
    }
}
exports.createWorkspaces = createWorkspaces;
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
exports.sleep = sleep;
//# sourceMappingURL=workspaces.js.map