"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseProjectResolver = void 0;
//#region imports
const lib_1 = require("tnp-core/lib");
const lib_2 = require("tnp-core/lib");
const lib_3 = require("tnp-core/lib");
const lib_4 = require("tnp-core/lib");
const build_info__auto_generated_1 = require("../../build-info._auto-generated_");
const config_database_1 = require("../config-database");
const project_database_1 = require("../project-database");
const tcp_udp_ports_1 = require("../tcp-udp-ports");
//#endregion
class BaseProjectResolver {
    classFn;
    cliToolNameFn;
    configDb = new config_database_1.ConfigDatabase(this);
    projectsDb = new project_database_1.ProjectDatabase(this);
    /**
     * Assign it to do a clean up before exit program
     */
    exitProgramCleaningFn;
    async editor() {
        return (lib_1.UtilsOs.detectEditor() || (await this.configDb.codeEditor.getValue()));
    }
    portsWorker;
    //#region fields
    NPM_PROJECT_KEY = 'npm';
    projects = [];
    /**
     * To speed up checking folder I am keeping paths for already checked folder
     * This may break things that are creating new projects
     */
    emptyLocations = [];
    //#endregion
    //#region constructor
    constructor(classFn, cliToolNameFn) {
        this.classFn = classFn;
        this.cliToolNameFn = cliToolNameFn;
        // console.log("global.frameworkName",global.frameworkName)
        // if (!UtilsOs.isRunningInVscodeExtension()) {
        // if (!this.cliToolName) {
        //   Helpers.throw(`cliToolName is not provided`);
        // }
        if (cliToolNameFn) {
            this.portsWorker = new tcp_udp_ports_1.PortsWorker('ports-worker', // BaseGlobalCommandLine.prototype.startCliServicePortsWorker
            () => `${cliToolNameFn()} startCliServicePortsWorker --skipCoreCheck`, build_info__auto_generated_1.CURRENT_PACKAGE_VERSION);
        }
    }
    //#endregion
    //#region fields & getters / allowed types
    get allowedTypes() {
        //#region @websqlFunc
        return [this.NPM_PROJECT_KEY];
        // throw `Please override this getter [allowedTypes] in your child class or  ${CLI.chalk.bold(config.frameworkName)}`;
        //#endregion
    }
    //#endregion
    //#region fields & getters / current project
    /**
     * project from process.cwd()
     */
    get Current() {
        //#region @backendFunc
        const current = this.classFn.ins.From(process.cwd());
        if (!current) {
            //   Helpers.warn(`[taon-helpers] Current location is not a ${CLI.chalk.bold(config.frameworkName)} type project.
            //  location: "${process.cwd()}"
            //  }`);
            return void 0;
        }
        return current;
        //#endregion
    }
    //#endregion
    //#region fields & getters / resolve type from
    /**
     * override this
     */
    typeFrom(location, recrusiveCall = false) {
        //#region @backendFunc
        if (lib_4.Helpers.exists((0, lib_3.crossPlatformPath)([location, lib_1.config.file.package_json]))) {
            return this.NPM_PROJECT_KEY;
        }
        if (recrusiveCall) {
            return;
        }
        // throw `Please override this function [typeFrom] in your child class or  ${CLI.chalk.bold(config.frameworkName)}`;
        //#endregion
    }
    //#endregion
    //#region fields & getters / from
    From(locationOfProject, options) {
        // console.log({
        //   locationOfProj
        // })
        //#region @websqlFunc
        if (Array.isArray(locationOfProject)) {
            locationOfProject = locationOfProject.join('/');
        }
        let location = (0, lib_3.crossPlatformPath)(locationOfProject.replace(/\/\//g, '/'));
        if (!lib_4._.isString(location)) {
            lib_4.Helpers.warn(`[project.from] location is not a string`);
            return;
        }
        if (lib_3.path.basename(location) === 'dist') {
            location = lib_3.path.dirname(location);
        }
        location = (0, lib_3.crossPlatformPath)(lib_3.path.resolve(location));
        const alreadyExist = this.projects.find(l => l.location.trim() === location.trim());
        if (alreadyExist) {
            return alreadyExist;
        }
        //#region @backend
        if (!lib_2.fse.existsSync(location)) {
            lib_4.Helpers.log(`[taon-helpers][project.from] Cannot find project in location: ${location}`, 1);
            this.emptyLocations.push(location);
            return;
        }
        let type = this.typeFrom(location);
        if (type) {
            let resultProject = new this.classFn();
            const pj = lib_4.Helpers.readJson((0, lib_3.crossPlatformPath)([location, lib_1.config.file.package_json]));
            // @ts-ignore
            resultProject.location = location;
            // @ts-ignore
            resultProject.type = type;
            // @ts-ignore
            resultProject.packageJSON = pj;
            // @ts-ignore
            resultProject.ins = this;
            return resultProject;
        }
        //#endregion
        //#endregion
    }
    //#endregion
    //#region fields & getters / get project nearest to path
    nearestTo(absoluteLocation, options) {
        //#region @backendFunc
        if (Array.isArray(absoluteLocation)) {
            absoluteLocation = (0, lib_3.crossPlatformPath)(absoluteLocation);
        }
        options = options || {};
        const { type, findGitRoot, onlyOutSideNodeModules } = options;
        if (lib_4._.isString(type) && !this.allowedTypes.includes(type)) {
            lib_4.Helpers.error(`[taon-helpers][project.nearestTo] wrong type: ${type}`, false, true);
        }
        if (lib_2.fse.existsSync(absoluteLocation)) {
            absoluteLocation = lib_2.fse.realpathSync(absoluteLocation);
        }
        if (lib_2.fse.existsSync(absoluteLocation) &&
            !lib_2.fse.lstatSync(absoluteLocation).isDirectory()) {
            absoluteLocation = lib_3.path.dirname(absoluteLocation);
        }
        let project;
        let previousLocation;
        while (true) {
            if (onlyOutSideNodeModules &&
                lib_3.path.basename(lib_3.path.dirname(absoluteLocation)) ===
                    'node_modules') {
                absoluteLocation = lib_3.path.dirname(lib_3.path.dirname(absoluteLocation));
            }
            project = this.From(absoluteLocation, options);
            // console.log(`is project  ${!!project} ${absoluteLocation}`);
            if (lib_4._.isString(type)) {
                if (this.allowedTypes.includes(project?.type)) {
                    if (findGitRoot) {
                        if (project.git.isGitRoot) {
                            break;
                        }
                    }
                    else {
                        break;
                    }
                }
            }
            else {
                if (project) {
                    if (findGitRoot) {
                        if (project.git.isGitRoot) {
                            break;
                        }
                    }
                    else {
                        break;
                    }
                }
            }
            previousLocation = absoluteLocation;
            const newAbsLocation = lib_3.path.join(absoluteLocation, '..');
            if (!lib_3.path.isAbsolute(newAbsLocation)) {
                return;
            }
            absoluteLocation = (0, lib_3.crossPlatformPath)(lib_3.path.resolve(newAbsLocation));
            if (!lib_2.fse.existsSync(absoluteLocation) &&
                absoluteLocation.split('/').length < 2) {
                return;
            }
            if (previousLocation === absoluteLocation) {
                return;
            }
        }
        return project;
        //#endregion
    }
    //#endregion
    //#region fields & getters / unload project
    unload(projectOrLocationOfProject) {
        const location = lib_4._.isString(projectOrLocationOfProject)
            ? projectOrLocationOfProject
            : projectOrLocationOfProject?.location;
        this.projects = this.projects.filter(f => f.location !== location);
        this.emptyLocations = this.emptyLocations.filter(f => f !== location);
    }
    //#endregion
    //#region fields & getters / remove project
    remove(project) {
        //#region @backend
        const location = project.location;
        this.projects = this.projects.filter(p => p.location !== location);
        //#endregion
    }
    //#endregion
    //#region fields & getters / manually add project
    add(project) {
        //#region @backend
        this.projects.push(project);
        //#endregion
    }
    //#endregion
    //#region fields & getters / all projects from location
    allProjectFrom(absoluteLocation, stopOnCwd = '/') {
        //#region @backendFunc
        const projects = {};
        const projectsList = [];
        let previousAbsLocation;
        stopOnCwd = (0, lib_3.crossPlatformPath)(stopOnCwd);
        absoluteLocation = (0, lib_3.crossPlatformPath)(absoluteLocation);
        while (absoluteLocation.startsWith(stopOnCwd)) {
            if (previousAbsLocation === absoluteLocation) {
                break;
            }
            const proj = this.nearestTo(absoluteLocation);
            if (proj) {
                if (projects[proj.location]) {
                    break;
                }
                projects[proj.location] = proj;
                projectsList.push(proj);
                previousAbsLocation = absoluteLocation;
                absoluteLocation = (0, lib_3.crossPlatformPath)(lib_3.path.dirname(proj.location));
                continue;
            }
            break;
        }
        return projectsList;
        //#endregion
    }
    allProjectsFromFolder(folderLocation) {
        //#region @backendFunc
        return lib_4.Helpers.foldersFrom(folderLocation, { recursive: false })
            .map(f => this.From(f))
            .filter(f => !!f);
        //#endregion
    }
    //#endregion
    //#region fields & getters / sort group of projects
    sortGroupOfProject(projects, resoveDepsArray, projNameToCompare, projUniqueKeyToCompare, overridePackagesOrder = []) {
        return lib_1.UtilsProjects.sortGroupOfProject({
            projects,
            resoveDepsArray,
            projNameToCompare,
            projUniqueKeyToCompare,
            overridePackagesOrder,
        });
    }
}
exports.BaseProjectResolver = BaseProjectResolver;
//# sourceMappingURL=base-project-resolver.js.map