"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateImportsProviderImpl = void 0;
const path_1 = __importDefault(require("path"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../../lib/documents");
const utils_1 = require("../../../utils");
const utils_2 = require("../utils");
const utils_3 = require("./utils");
class UpdateImportsProviderImpl {
    constructor(lsAndTsDocResolver) {
        this.lsAndTsDocResolver = lsAndTsDocResolver;
    }
    async updateImports(fileRename) {
        var _a, _b, _c;
        // TODO does this handle folder moves/renames correctly? old/new path isn't a file then
        const oldPath = (0, utils_1.urlToPath)(fileRename.oldUri);
        const newPath = (0, utils_1.urlToPath)(fileRename.newUri);
        if (!oldPath || !newPath) {
            return null;
        }
        const ls = await this.getLSForPath(newPath);
        const oldPathTsProgramCasing = (_c = (_b = (_a = ls.getProgram()) === null || _a === void 0 ? void 0 : _a.getSourceFile(oldPath)) === null || _b === void 0 ? void 0 : _b.fileName) !== null && _c !== void 0 ? _c : oldPath;
        // `getEditsForFileRename` might take a while
        const fileChanges = ls
            .getEditsForFileRename(oldPathTsProgramCasing, newPath, {}, {})
            // Assumption: Updating imports will not create new files, and to make sure just filter those out
            // who - for whatever reason - might be new ones.
            .filter((change) => !change.isNewFile || change.fileName === oldPathTsProgramCasing);
        await this.lsAndTsDocResolver.updateSnapshotPath(oldPathTsProgramCasing, newPath);
        const editInOldPath = fileChanges.find((change) => change.fileName.startsWith(oldPathTsProgramCasing) &&
            (oldPathTsProgramCasing.includes(newPath) || !change.fileName.startsWith(newPath)));
        const editInNewPath = fileChanges.find((change) => change.fileName.startsWith(newPath) &&
            (newPath.includes(oldPathTsProgramCasing) ||
                !change.fileName.startsWith(oldPathTsProgramCasing)));
        const updateImportsChanges = fileChanges
            .filter((change) => {
            if ((0, utils_3.isKitTypePath)(change.fileName)) {
                // These types are generated from the route files, so we don't want to update them
                return false;
            }
            if (!editInOldPath || !editInNewPath) {
                return true;
            }
            // If both present, take the one that has more text changes to it (more likely to be the correct one)
            return editInOldPath.textChanges.length > editInNewPath.textChanges.length
                ? change !== editInNewPath
                : change !== editInOldPath;
        })
            .map((change) => {
            if (change === editInOldPath) {
                // The language service might want to do edits to the old path, not the new path -> rewire it.
                // If there is a better solution for this, please file a PR :)
                change.fileName = change.fileName.replace(oldPathTsProgramCasing, newPath);
            }
            change.textChanges = change.textChanges.filter((textChange) => 
            // Filter out changes to './$type' imports for Kit route files,
            // you'll likely want these to stay as-is
            !(0, utils_3.isKitTypePath)(textChange.newText) ||
                !path_1.default.basename(change.fileName).startsWith('+'));
            return change;
        });
        const docs = new utils_3.SnapshotMap(this.lsAndTsDocResolver);
        const documentChanges = await Promise.all(updateImportsChanges.map(async (change) => {
            const snapshot = await docs.retrieve(change.fileName);
            return vscode_languageserver_1.TextDocumentEdit.create(vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create(snapshot.getURL(), null), change.textChanges.map((edit) => {
                const range = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, edit.span));
                return vscode_languageserver_1.TextEdit.replace(range, edit.newText);
            }));
        }));
        return { documentChanges };
    }
    async getLSForPath(path) {
        return this.lsAndTsDocResolver.getLSForPath(path);
    }
}
exports.UpdateImportsProviderImpl = UpdateImportsProviderImpl;
//# sourceMappingURL=UpdateImportsProvider.js.map