import { config } from 'tnp-core/lib';
import { _, crossPlatformPath, path } from 'tnp-core/lib';
import { Helpers } from 'tnp-core/lib';
import { BaseJsonFileReader, } from './base-json-file-reader';
export const PackageJsonDependencyObjArr = [
    'dependencies',
    'devDependencies',
    'peerDependencies',
    'resolutions',
];
//#endregion
export class BasePackageJson extends BaseJsonFileReader {
    constructor(options) {
        super({ ...options, fileName: config.file.package_json });
    }
    //#region name
    /**
     * 'dependencies'
     * 'devDependencies'
     * 'peerDependencies'
     * 'resolutions';
     * and whatever is in package.json to npm install
     */
    get dependenciesTypesArray() {
        return PackageJsonDependencyObjArr;
    }
    get name() {
        return this.data?.name || '';
    }
    get exists() {
        return Helpers.exists(this.path);
    }
    async setName(name) {
        //#region @backendFunc
        if (!this.data) {
            Helpers.warn(`[taon][setName] Package.json not exist in ${this.cwd}`);
            return;
        }
        this.data.name = name;
        this.saveToDisk('setting new name');
        //#endregion
    }
    //#endregion
    //#region dev dependencies
    /**
     * devDependencies dependencies
     */
    get devDependencies() {
        return _.cloneDeep(this.data ? this.data.devDependencies : {}) || {};
    }
    //#endregion
    //#region resolutions dependencies
    /**
     * resolutions dependencies
     */
    get resolutions() {
        return _.cloneDeep(this.data ? this.data['resolutions'] : {}) || {};
    }
    //#endregion
    //#region dependencies
    /**
     * npm dependencies from package.json
     */
    get dependencies() {
        return _.cloneDeep(this.data ? this.data.dependencies : {}) || {};
    }
    get optionalDependencies() {
        return _.cloneDeep(this.data ? this.data.optionalDependencies : {}) || {};
    }
    get description() {
        return this.data?.description || '';
    }
    get displayName() {
        return this.data.displayName || '';
    }
    get license() {
        return this.data.license || '';
    }
    get publisher() {
        return this.data.publisher || '';
    }
    get contributes() {
        return this.data?.contributes;
    }
    get repository() {
        return this.data?.repository;
    }
    setRepository(repository) {
        this.data.repository = repository;
        this.saveToDisk('setting repository');
    }
    /**
     * set the WHOLE dependencies object
     * THIS WILL NOT MERGE -> IT WILL REPLACE WHOLE DEPENDENCIES OBJECT
     */
    setDependencies(dependencies) {
        if (!this.data) {
            Helpers.warn(`[taon][setDependencies] Package.json not exist in ${this.cwd}`);
            return;
        }
        this.data.dependencies = dependencies;
        this.saveToDisk();
    }
    //#endregion
    /**
     * set the WHOLE dependencies object
     * THIS WILL NOT MERGE -> IT WILL REPLACE WHOLE DEPENDENCIES OBJECT
     */
    setDevDependencies(devDependencies) {
        if (!this.data) {
            Helpers.warn(`[taon][setDevDependencies] Package.json not exist in ${this.cwd}`);
            return;
        }
        this.data.devDependencies = devDependencies;
        this.saveToDisk();
    }
    //#endregion
    //#region peer dependencies
    /**
     * peerDependencies dependencies
     */
    get peerDependencies() {
        return _.cloneDeep(this.data ? this.data.peerDependencies : {}) || {};
    }
    /**
     * set the WHOLE peerDependencies object
     * THIS WILL NOT MERGE -> IT WILL REPLACE WHOLE PEER DEPENDENCIES OBJECT
     */
    setPeerDependencies(peerDependencies) {
        if (!this.data) {
            Helpers.warn(`[taon][setPeerDependencies] Package.json not exist in ${this.cwd}`);
            return;
        }
        this.data.peerDependencies = peerDependencies;
        this.saveToDisk();
    }
    //#endregion
    setOptionalDependencies(optionalDependencies) {
        if (!this.data) {
            Helpers.warn(`[taon][setOptionalDependencies] Package.json not exist in ${this.cwd}`);
            return;
        }
        this.data.optionalDependencies = optionalDependencies;
        this.saveToDisk();
    }
    //#endregion
    //#region remove dev dependencies
    removeDevDependencies() {
        if (!this.data) {
            Helpers.warn(`[taon][removeDevDependencies] Package.json not exist in ${this.cwd}`);
            return;
        }
        try {
            delete this.data.devDependencies;
        }
        catch (error) { }
        this.saveToDisk();
    }
    //#endregion
    //#region all dependencies
    /**
     * @returns object witl all deps from current project package json
     */
    get allDependencies() {
        return this.allDepsFromPackageJson(this.data);
    }
    /**
     * @returns object witl all deps from package json
     */
    allDepsFromPackageJson(packageJson) {
        return _.cloneDeep(_.merge({
            ...PackageJsonDependencyObjArr.reduce((acc, depObj) => {
                return {
                    ...acc,
                    ...(packageJson[depObj] || {}),
                };
            }, {}),
        }));
    }
    //#endregion
    //#region version
    /**
     * version from package.json -> property version
     */
    get version() {
        return this.data?.version;
    }
    setVersion(version) {
        //#region @backendFunc
        this.data.version = version;
        this.saveToDisk('setting new version');
        //#endregion
    }
    //#endregion
    //#region bin
    /**
     * bin with cli config from package.json
     */
    get bin() {
        return _.cloneDeep(this.data?.bin || {});
    }
    set bin(value) {
        this.data.bin = value;
        this.saveToDisk('setting bin');
    }
    //#endregion
    //#region engines
    get engines() {
        return _.cloneDeep(this.data.engines);
    }
    async setEngines(engines) {
        //#region @backendFunc
        let enginesString;
        try {
            enginesString = JSON.stringify(engines);
        }
        catch (error) {
            enginesString = `< CAN'T PARSE ENGINES >`;
        }
        Helpers.info(`Setting engines to project  ${this.cwd}: ${enginesString}`);
        this.data.engines = engines;
        this.saveToDisk('setting new engines');
        //#endregion
    }
    //#endregion
    //#region homepage
    get homepage() {
        return _.cloneDeep(this.data.homepage);
    }
    async setHomepage(homepage) {
        //#region @backendFunc
        Helpers.info(`Setting homepage property to ${this.cwd}/${this.fileName} : ${homepage}`);
        this.data.homepage = homepage;
        this.saveToDisk('setting new engines');
        //#endregion
    }
    //#endregion
    //#region version with patch plus one
    get versionWithPatchPlusOne() {
        const ver = this.version.split('.');
        if (ver.length > 0) {
            ver[ver.length - 1] = (parseInt(_.last(ver)) + 1).toString();
        }
        return ver.join('.');
    }
    //#endregion
    //#region version with minor plus one and path zero
    get versionWithMinorPlusOneAndPatchZero() {
        const ver = this.version.split('.');
        if (ver.length > 1) {
            ver[1] = (parseInt(ver[1]) + 1).toString();
            for (let index = 2; index < ver.length; index++) {
                ver[index] = '0';
            }
        }
        else {
            Helpers.warn(`[npm-project] something went wrong with bumping minor version`);
        }
        return ver.join('.');
    }
    //#endregion
    //#region version with major plus one and minor zero and patch zero
    get versionWithMajorPlusOneAndMinorZeroAndPatchZero() {
        const ver = this.version.split('.');
        if (ver.length > 0) {
            ver[0] = (parseInt(_.first(ver)) + 1).toString();
            for (let index = 1; index < ver.length; index++) {
                ver[index] = '0';
            }
        }
        else {
            Helpers.warn(`[npm-project] something went wrong with bumping major version`);
        }
        return ver.join('.');
    }
    //#endregion
    //#region get version path as number
    get versionPathAsNumber() {
        //#region @backendFunc
        const ver = this.version.split('.');
        const res = Number(_.last(ver));
        return isNaN(res) ? 0 : res;
        //#endregion
    }
    //#endregion
    //#region major version
    /**
     * Major Version from package.json
     */
    // @ts-ignore
    get majorVersion() {
        //#region @backendFunc
        return Number(_.first((this.version || '').split('.')));
        //#endregion
    }
    //#endregion
    //#region minor version
    /**
     * Minor Version from package.json
     */
    // @ts-ignore
    get minorVersion() {
        //#region @backendFunc
        const [__, minor] = (this.version || '').split('.') || [void 0, void 0];
        return Number(minor);
        //#endregion
    }
    //#endregion
    //#region get version as number
    /**
     * @deprecated TODO not usefull ?
     */
    getVersionAsNumber(releaseType) {
        if (releaseType === 'patch') {
            return this.versionPathAsNumber;
        }
        if (releaseType === 'minor') {
            return this.minorVersion;
        }
        if (releaseType === 'major') {
            return this.majorVersion;
        }
    }
    //#endregion
    //#region bump path version
    async bumpPatchVersion() {
        //#region @backendFunc
        // Read package.json
        const version = this.data?.version;
        if (!version) {
            this.setVersion('0.0.0');
            return;
        }
        const versionComponents = version.match(/^(\d+)\.(\d+)\.(\d+)(-.+)?$/);
        const major = versionComponents[1];
        const minor = versionComponents[2];
        const patch = versionComponents[3];
        const preRelease = versionComponents[4] || '';
        // Increment the patch version
        const newPatch = parseInt(patch, 10) + 1;
        // Construct the new version
        const newVersion = `${major}.${minor}.${newPatch}${preRelease}`;
        this.setVersion(newVersion);
        //#endregion
    }
    //#endregion
    //#region getters & methods / get version for
    getBumpedVersionFor(releaseType) {
        //#region @backendFunc
        if (releaseType === 'patch') {
            return this.versionWithPatchPlusOne;
        }
        if (releaseType === 'minor') {
            return this.versionWithMinorPlusOneAndPatchZero;
        }
        if (releaseType === 'major') {
            return this.versionWithMajorPlusOneAndMinorZeroAndPatchZero;
        }
        //#endregion
    }
    getBumpedOrCurrentVersionFor(releaseType) {
        //#region @backendFunc
        if (releaseType) {
            return this.getBumpedVersionFor(releaseType);
        }
        else {
            return this.version;
        }
        //#endregion
    }
    //#endregion
    //#region update deps from locations
    updateDepsFrom(locations) {
        //#region @backendFunc
        locations.forEach(location => {
            const packageJson = Helpers.readJson(location, config.file.package_json);
            const deps = this.allDepsFromPackageJson(packageJson);
            Object.keys(deps).forEach(dep => {
                if (this.dependencies[dep]) {
                    this.dependencies[dep] = deps[dep];
                }
            });
        });
        this.saveToDisk();
        //#endregion
    }
    //#endregion
    //#region update dependency
    /**
     * this will NOT SET dependency if
     * dependency name is not in package.json
     */
    updateDependency({ packageName, version, createNewEntryIfNotExist, }) {
        //#region @backendFunc
        let exists = false;
        for (const depsName of PackageJsonDependencyObjArr) {
            if (this.data[depsName] && this.data[depsName][packageName]) {
                exists = true;
                if (version === null) {
                    delete this.data[depsName][packageName];
                }
                else {
                    this.data[depsName][packageName] = version;
                }
            }
        }
        if (createNewEntryIfNotExist && !exists && version !== null) {
            this.data['dependencies'] = this.data['dependencies'] || {};
            this.data['dependencies'][packageName] = version;
        }
        this.saveToDisk();
        //#endregion
    }
    //#endregion
    //#region is private
    get isPrivate() {
        //#region @backendFunc
        return !!this.data?.private;
        //#endregion
    }
    setIsPrivate(value) {
        //#region @backendFunc
        this.data.private = value;
        this.saveToDisk('setting private');
        //#endregion
    }
    //#endregion
    //#region side effects
    get sideEffects() {
        //#region @backendFunc
        return !!this.data?.sideEffects;
        //#endregion
    }
    //#endregion
    //#region set new version
    async setMainProperty(main, purpose = '') {
        //#region @backendFunc
        Helpers.info(`Setting main property in  ${this.cwd}: ${main}/${this.fileName}`);
        this.data.main = main;
        this.saveToDisk(`setting main version ` + purpose ? `[${purpose}]` : '');
        //#endregion
    }
    //#endregion
    //#region build hash
    setBuildHash(hash) {
        this.data.lastBuildTagHash = hash;
        this.saveToDisk('setting build hash');
    }
    getBuildHash() {
        return this.data.lastBuildTagHash;
    }
    //#endregion
    //#region copyto
    copyTo(location) {
        //#region @backendFunc
        location = crossPlatformPath(location);
        if (location.endsWith(config.file.package_json)) {
            location = crossPlatformPath(path.dirname(location));
        }
        Helpers.writeJson([location, config.file.package_json], this.data);
        //#endregion
    }
}
//# sourceMappingURL=base-package-json.js.map