/**
 * Copyright 2013-2026 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { uniqBy } from 'lodash-es';
import { APPLICATION_TYPE_KEY } from "../core/application-types.js";
import { getDefaultRuntime } from "../jdl-config/jhipster-jdl-config.js";
import { readCurrentPathYoRcFile } from "../utils/yo-rc.js";
import { formatApplicationToExport, formatApplicationsToExport, } from "./converters/exporters/applications/jhipster-application-formatter.js";
import { GENERATOR_NAME } from "./converters/exporters/export-utils.js";
import exportDeployments from "./converters/exporters/jhipster-deployment-exporter.js";
import exportEntities from "./converters/exporters/jhipster-entity-exporter.js";
import { convert } from "./converters/jdl-to-json/jdl-with-applications-to-json-converter.js";
import JDLWithoutApplicationToJSONConverter from "./converters/jdl-to-json/jdl-without-application-to-json-converter.js";
import ParsedJDLToJDLObjectConverter from "./converters/parsed-jdl-to-jdl-object/parsed-jdl-to-jdl-object-converter.js";
import createWithApplicationValidator from "./converters/validators/jdl-with-application-validator.js";
import createWithoutApplicationValidator from "./converters/validators/jdl-without-application-validator.js";
import { BASE_NAME_KEY } from "./core/built-in-options/index.js";
import { parseFromContent, parseFromFiles } from "./core/readers/jdl-reader.js";
import { createRuntime } from "./core/runtime.js";
const GENERATOR_JHIPSTER = 'generator-jhipster'; // can't use the one of the generator as it circles
/**
 * Creates a new JDL importer from files.
 * There are two ways to create an importer:
 *   - By providing an existing application content, if there's one
 *   - Deprecated: providing some application options
 */
export function createImporterFromFiles(files, configuration, definition) {
    if (!files) {
        throw new Error('Files must be passed to create a new JDL importer.');
    }
    const runtime = definition ? createRuntime(definition) : getDefaultRuntime();
    const content = parseFromFiles(files, runtime);
    return makeJDLImporter(content, configuration || {}, runtime);
}
/**
 * Creates a new JDL importer from a JDL string content.
 * There are two ways to create an importer:
 *   - By providing an existing application content, if there's one
 *   - Deprecated: providing some application options
 */
export function createImporterFromContent(jdlString, configuration, definition) {
    if (!jdlString) {
        throw new Error('A JDL content must be passed to create a new JDL importer.');
    }
    const runtime = definition ? createRuntime(definition) : getDefaultRuntime();
    const content = parseFromContent(jdlString, runtime);
    return makeJDLImporter(content, configuration || {}, runtime);
}
function makeJDLImporter(content, configuration, runtime) {
    let importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    return {
        /**
         * Processes JDL files and converts them to JSON.
         * @returns {object} the state of the process:
         *          - exportedDeployments: the exported deployments, or an empty list
         *          - exportedApplications: the exported applications, or an empty list
         *          - exportedEntities: the exported entities, or an empty list
         */
        import: () => {
            const jdlObject = getJDLObject(content, configuration, runtime);
            checkForErrors(jdlObject);
            if (jdlObject.getApplicationQuantity() === 0 && jdlObject.getEntityQuantity() > 0) {
                importState.exportedEntities = importOnlyEntities(jdlObject, configuration);
            }
            else if (jdlObject.getApplicationQuantity() === 1) {
                importState = importOneApplicationAndEntities(jdlObject);
            }
            else {
                importState = importApplicationsAndEntities(jdlObject);
            }
            if (jdlObject.getDeploymentQuantity()) {
                importState.exportedDeployments = importDeployments(jdlObject.deployments);
            }
            return importState;
        },
    };
}
function getJDLObject(parsedJDLContent, configuration, runtime) {
    let baseName = configuration.applicationName;
    let { applicationType } = configuration;
    if (configuration.application) {
        baseName ??= configuration.application[GENERATOR_JHIPSTER].baseName;
        applicationType ??= configuration.application[GENERATOR_JHIPSTER].applicationType;
    }
    return ParsedJDLToJDLObjectConverter.parseFromConfigurationObject({
        parsedContent: parsedJDLContent,
        applicationType,
        applicationName: baseName,
    }, runtime);
}
function checkForErrors(jdlObject) {
    let validator;
    if (jdlObject.getApplicationQuantity() === 0) {
        validator = createWithoutApplicationValidator(jdlObject);
    }
    else {
        validator = createWithApplicationValidator(jdlObject);
    }
    validator.checkForErrors();
}
function importOnlyEntities(jdlObject, configuration) {
    let { applicationName } = configuration;
    let { application } = configuration;
    application ??= readCurrentPathYoRcFile();
    if (application?.[GENERATOR_JHIPSTER]) {
        applicationName ??= application[GENERATOR_JHIPSTER].baseName;
    }
    const entitiesPerApplicationMap = JDLWithoutApplicationToJSONConverter.convert(jdlObject, applicationName);
    const jsonEntities = entitiesPerApplicationMap.get(applicationName);
    return exportJSONEntities(jsonEntities, configuration);
}
function importOneApplicationAndEntities(jdlObject) {
    const importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    const formattedApplication = formatApplicationToExport(jdlObject.getApplications()[0]);
    importState.exportedApplications.push(formattedApplication);
    const jdlApplication = jdlObject.getApplications()[0];
    const applicationName = jdlApplication.getConfigurationOptionValue(BASE_NAME_KEY);
    const entitiesPerApplicationMap = convert(jdlObject);
    const jsonEntities = entitiesPerApplicationMap.get(applicationName);
    const { [GENERATOR_NAME]: config, ...remaining } = formattedApplication;
    importState.exportedApplicationsWithEntities[applicationName] = {
        config,
        ...remaining,
        entities: [],
    };
    if (jsonEntities.length !== 0) {
        const exportedJSONEntities = exportJSONEntities(jsonEntities, {
            applicationName,
            applicationType: jdlApplication.getConfigurationOptionValue(APPLICATION_TYPE_KEY),
            forSeveralApplications: false,
        });
        importState.exportedApplicationsWithEntities[applicationName].entities = exportedJSONEntities;
        importState.exportedEntities = uniqBy([...importState.exportedEntities, ...exportedJSONEntities], 'name');
    }
    return importState;
}
function importApplicationsAndEntities(jdlObject) {
    const importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    const formattedApplications = formatApplicationsToExport(jdlObject.applications);
    importState.exportedApplications = formattedApplications;
    const entitiesPerApplicationMap = convert(jdlObject);
    entitiesPerApplicationMap.forEach((jsonEntities, applicationName) => {
        const jdlApplication = jdlObject.getApplication(applicationName);
        const exportedJSONEntities = exportJSONEntities(jsonEntities, {
            applicationName,
            applicationType: jdlApplication.getConfigurationOptionValue(APPLICATION_TYPE_KEY),
            forSeveralApplications: true,
        });
        const exportedConfig = importState.exportedApplications.find(config => applicationName === config['generator-jhipster'].baseName);
        const { 'generator-jhipster': config, ...remaining } = exportedConfig;
        importState.exportedApplicationsWithEntities[applicationName] = {
            config,
            ...remaining,
            entities: exportedJSONEntities,
        };
        importState.exportedEntities = uniqBy([...importState.exportedEntities, ...exportedJSONEntities], 'name');
    });
    return importState;
}
function importDeployments(deployments) {
    return exportDeployments(deployments);
}
function exportJSONEntities(entities, configuration) {
    let baseName = configuration.applicationName;
    let { applicationType } = configuration;
    if (configuration.application) {
        ({ baseName, applicationType } = configuration.application[GENERATOR_JHIPSTER]);
    }
    return exportEntities({
        entities,
        application: {
            name: baseName,
            type: applicationType,
            forSeveralApplications: !!configuration.forSeveralApplications,
        },
    });
}
