//#region imports
import { config, UtilsOs__NS__detectEditor, UtilsProjects__NS__sortGroupOfProject } from 'tnp-core/lib-prod';
import { fse } from 'tnp-core/lib-prod';
import { path, crossPlatformPath } from 'tnp-core/lib-prod';
import { ___NS__isString, Helpers__NS__error, Helpers__NS__exists, Helpers__NS__foldersFrom, Helpers__NS__log, Helpers__NS__readJson, Helpers__NS__warn } from 'tnp-core/lib-prod';
import { CURRENT_PACKAGE_VERSION } from '../../build-info._auto-generated_';
import { ConfigDatabase } from '../config-database';
import { ProjectDatabase } from '../project-database';
import { PortsWorker } from '../tcp-udp-ports';
//#endregion
export class BaseProjectResolver {
    classFn;
    cliToolNameFn;
    configDb = new ConfigDatabase(this);
    projectsDb = new ProjectDatabase(this);
    /**
     * Assign it to do a clean up before exit program
     */
    exitProgramCleaningFn;
    async editor() {
        return (UtilsOs__NS__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__NS__isRunningInVscodeExtension()) {
        // if (!this.cliToolName) {
        //   Helpers.throw(`cliToolName is not provided`);
        // }
        if (cliToolNameFn) {
            this.portsWorker = new PortsWorker('ports-worker', // BaseGlobalCommandLine.prototype.startCliServicePortsWorker
            () => `${cliToolNameFn()} startCliServicePortsWorker --skipCoreCheck`, 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__NS__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 (Helpers__NS__exists(crossPlatformPath([location, 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 = crossPlatformPath(locationOfProject.replace(/\/\//g, '/'));
        if (!___NS__isString(location)) {
            Helpers__NS__warn(`[project.from] location is not a string`);
            return;
        }
        if (path.basename(location) === 'dist') {
            location = path.dirname(location);
        }
        location = crossPlatformPath(path.resolve(location));
        const alreadyExist = this.projects.find(l => l.location.trim() === location.trim());
        if (alreadyExist) {
            return alreadyExist;
        }
        //#region @backend
        if (!fse.existsSync(location)) {
            Helpers__NS__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 = Helpers__NS__readJson(crossPlatformPath([location, 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 = crossPlatformPath(absoluteLocation);
        }
        options = options || {};
        const { type, findGitRoot, onlyOutSideNodeModules } = options;
        if (___NS__isString(type) && !this.allowedTypes.includes(type)) {
            Helpers__NS__error(`[taon-helpers][project.nearestTo] wrong type: ${type}`, false, true);
        }
        if (fse.existsSync(absoluteLocation)) {
            absoluteLocation = fse.realpathSync(absoluteLocation);
        }
        if (fse.existsSync(absoluteLocation) &&
            !fse.lstatSync(absoluteLocation).isDirectory()) {
            absoluteLocation = path.dirname(absoluteLocation);
        }
        let project;
        let previousLocation;
        while (true) {
            if (onlyOutSideNodeModules &&
                path.basename(path.dirname(absoluteLocation)) ===
                    'node_modules') {
                absoluteLocation = path.dirname(path.dirname(absoluteLocation));
            }
            project = this.From(absoluteLocation, options);
            // console.log(`is project  ${!!project} ${absoluteLocation}`);
            if (___NS__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 = path.join(absoluteLocation, '..');
            if (!path.isAbsolute(newAbsLocation)) {
                return;
            }
            absoluteLocation = crossPlatformPath(path.resolve(newAbsLocation));
            if (!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 = ___NS__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 = crossPlatformPath(stopOnCwd);
        absoluteLocation = 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 = crossPlatformPath(path.dirname(proj.location));
                continue;
            }
            break;
        }
        return projectsList;
        //#endregion
    }
    allProjectsFromFolder(folderLocation) {
        //#region @backendFunc
        return Helpers__NS__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 UtilsProjects__NS__sortGroupOfProject({
            projects,
            resoveDepsArray,
            projNameToCompare,
            projUniqueKeyToCompare,
            overridePackagesOrder,
        });
    }
}
//# sourceMappingURL=c:/Users/darek/projects/npm/taon-dev/tnp-helpers/dist-nocutsrc-prod/lib/base/classes/base-project-resolver.js.map