"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = create;
const language_core_1 = require("@vue/language-core");
const volar_service_css_1 = require("volar-service-css");
const vscode_uri_1 = require("vscode-uri");
const utils_1 = require("../utils");
function create({ resolveModuleName }) {
    let modulePathCache;
    const baseService = (0, volar_service_css_1.create)({
        getDocumentContext(context) {
            return {
                resolveReference(ref, base) {
                    let baseUri = vscode_uri_1.URI.parse(base);
                    const decoded = context.decodeEmbeddedDocumentUri(baseUri);
                    if (decoded) {
                        baseUri = decoded[0];
                    }
                    if (modulePathCache
                        && baseUri.scheme === 'file'
                        && !ref.startsWith('./')
                        && !ref.startsWith('../')) {
                        const map = modulePathCache;
                        if (!map.has(ref)) {
                            const fileName = baseUri.fsPath.replace(/\\/g, '/');
                            const promise = resolveModuleName(fileName, ref, true);
                            map.set(ref, promise);
                            if (promise instanceof Promise) {
                                promise.then(res => map.set(ref, res));
                            }
                        }
                        const cached = modulePathCache.get(ref);
                        if (cached instanceof Promise) {
                            throw cached;
                        }
                        if (cached) {
                            return vscode_uri_1.URI.file(cached).toString();
                        }
                    }
                    return (0, volar_service_css_1.resolveReference)(ref, baseUri, context.env.workspaceFolders);
                },
            };
        },
        scssDocumentSelector: ['scss', 'postcss'],
    });
    return {
        ...baseService,
        create(context) {
            const baseServiceInstance = baseService.create(context);
            const { 'css/languageService': getCssLs, 'css/stylesheet': getStylesheet, } = baseServiceInstance.provide;
            return {
                ...baseServiceInstance,
                async provideDiagnostics(document, token) {
                    let diagnostics = await baseServiceInstance.provideDiagnostics?.(document, token) ?? [];
                    if (document.languageId === 'postcss') {
                        diagnostics = diagnostics.filter(diag => diag.code !== 'css-semicolonexpected'
                            && diag.code !== 'css-ruleorselectorexpected'
                            && diag.code !== 'unknownAtRules');
                    }
                    return diagnostics;
                },
                /**
                 * If the position is within the virtual code and navigation is enabled,
                 * skip the CSS navigation feature.
                 */
                provideReferences(document, position) {
                    if (isWithinNavigationVirtualCode(document, position)) {
                        return;
                    }
                    return worker(document, (stylesheet, cssLs) => {
                        return cssLs.findReferences(document, position, stylesheet);
                    });
                },
                provideRenameRange(document, position) {
                    if (isWithinNavigationVirtualCode(document, position)) {
                        return;
                    }
                    return worker(document, (stylesheet, cssLs) => {
                        return cssLs.prepareRename(document, position, stylesheet);
                    });
                },
                async provideDocumentLinks(document, token) {
                    modulePathCache = new Map();
                    while (true) {
                        try {
                            const result = await baseServiceInstance.provideDocumentLinks?.(document, token);
                            modulePathCache = undefined;
                            return result;
                        }
                        catch (e) {
                            if (e instanceof Promise) {
                                await e;
                            }
                            else {
                                throw e;
                            }
                        }
                    }
                },
            };
            function isWithinNavigationVirtualCode(document, position) {
                const info = (0, utils_1.resolveEmbeddedCode)(context, document.uri);
                if (!info?.code.id.startsWith('style_')) {
                    return false;
                }
                const block = info.root.ir.styles.find(style => style.name === info.code.id);
                if (!block) {
                    return false;
                }
                let script;
                for (const [key, value] of info.script.generated.embeddedCodes) {
                    if (key.startsWith('script_')) {
                        script = value;
                        break;
                    }
                }
                if (!script) {
                    return false;
                }
                const offset = document.offsetAt(position) + block.startTagEnd;
                for (const { sourceOffsets, lengths, data } of script.mappings) {
                    if (!sourceOffsets.length || !(0, language_core_1.isRenameEnabled)(data)) {
                        continue;
                    }
                    const start = sourceOffsets[0];
                    const end = sourceOffsets.at(-1) + lengths.at(-1);
                    if (offset >= start && offset <= end) {
                        return true;
                    }
                }
                return false;
            }
            function worker(document, callback) {
                const cssLs = getCssLs(document);
                if (!cssLs) {
                    return;
                }
                return callback(getStylesheet(document, cssLs), cssLs);
            }
        },
    };
}
//# sourceMappingURL=css.js.map