import * as _ from 'lodash-es';
import * as JDLReader from './readers/jdl-reader.js';
import ParsedJDLToJDLObjectConverter from './converters/parsed-jdl-to-jdl-object/parsed-jdl-to-jdl-object-converter.js';
import { readJSONFile } from './readers/json-file-reader.js';
import { doesFileExist } from './utils/file-utils.js';
import JDLWithoutApplicationToJSONConverter from './converters/jdl-to-json/jdl-without-application-to-json-converter.js';
import { convert } from './converters/jdl-to-json/jdl-with-applications-to-json-converter.js';
import { formatApplicationToExport, formatApplicationsToExport } from './exporters/applications/jhipster-application-formatter.js';
import exportDeployments from './exporters/jhipster-deployment-exporter.js';
import exportEntities from './exporters/jhipster-entity-exporter.js';
import createWithApplicationValidator from './validators/jdl-with-application-validator.js';
import createWithoutApplicationValidator from './validators/jdl-without-application-validator.js';
import { applicationOptions } from './jhipster/index.mjs';
const { OptionNames } = applicationOptions;
const { APPLICATION_TYPE, BASE_NAME } = OptionNames;
const { uniqBy } = _;
export function createImporterFromFiles(files, configuration) {
    if (!files) {
        throw new Error('Files must be passed to create a new JDL importer.');
    }
    const content = parseFiles(files);
    return makeJDLImporter(content, configuration || {});
}
export function createImporterFromContent(jdlString, configuration) {
    if (!jdlString) {
        throw new Error('A JDL content must be passed to create a new JDL importer.');
    }
    const content = JDLReader.parseFromContent(jdlString);
    return makeJDLImporter(content, configuration || {});
}
function makeJDLImporter(content, configuration) {
    let importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    return {
        import: (logger = console) => {
            const jdlObject = getJDLObject(content, configuration);
            checkForErrors(jdlObject, configuration, logger);
            if (jdlObject.getApplicationQuantity() === 0 && jdlObject.getEntityQuantity() > 0) {
                importState.exportedEntities = importOnlyEntities(jdlObject, configuration);
            }
            else if (jdlObject.getApplicationQuantity() === 1) {
                importState = importOneApplicationAndEntities(jdlObject, configuration);
            }
            else {
                importState = importApplicationsAndEntities(jdlObject, configuration);
            }
            if (jdlObject.getDeploymentQuantity()) {
                importState.exportedDeployments = importDeployments(jdlObject.deployments);
            }
            return importState;
        },
    };
}
function parseFiles(files) {
    return JDLReader.parseFromFiles(files);
}
function getJDLObject(parsedJDLContent, configuration) {
    let baseName = configuration.applicationName;
    let applicationType = configuration.applicationType;
    let databaseType = configuration.databaseType;
    if (configuration.application) {
        baseName = configuration.application['generator-begcode'].baseName;
        applicationType = configuration.application['generator-begcode'].applicationType;
        databaseType = configuration.application['generator-begcode'].databaseType;
    }
    return ParsedJDLToJDLObjectConverter.parseFromConfigurationObject({
        parsedContent: parsedJDLContent,
        applicationType,
        applicationName: baseName,
        databaseType,
    });
}
function checkForErrors(jdlObject, configuration, logger = console) {
    let validator;
    if (jdlObject.getApplicationQuantity() === 0) {
        let application = configuration.application;
        if (!application && doesFileExist('.yo-rc.json')) {
            application = readJSONFile('.yo-rc.json');
        }
        let applicationType = configuration.applicationType;
        let databaseType = configuration.databaseType;
        let blueprints = configuration.blueprints;
        if (application && application['generator-begcode']) {
            if (applicationType === undefined) {
                applicationType = application['generator-begcode'].applicationType;
            }
            if (databaseType === undefined) {
                databaseType = application['generator-begcode'].databaseType;
            }
            if (blueprints === undefined) {
                blueprints = application['generator-begcode'].blueprints;
            }
        }
        validator = createWithoutApplicationValidator(jdlObject, {
            applicationType,
            databaseType,
            blueprints,
        }, logger);
    }
    else {
        validator = createWithApplicationValidator(jdlObject, logger);
    }
    validator.checkForErrors();
}
function importOnlyEntities(jdlObject, configuration) {
    let { applicationName, applicationType, databaseType } = configuration;
    let application = configuration.application;
    if (!configuration.application && doesFileExist('.yo-rc.json')) {
        application = readJSONFile('.yo-rc.json');
    }
    if (application && application['generator-begcode']) {
        if (applicationType === undefined) {
            applicationType = application['generator-begcode'].applicationType;
        }
        if (applicationName === undefined) {
            applicationName = application['generator-begcode'].baseName;
        }
        if (databaseType === undefined) {
            databaseType = application['generator-begcode'].databaseType;
        }
    }
    const entitiesPerApplicationMap = JDLWithoutApplicationToJSONConverter.convert({
        jdlObject,
        applicationName,
        applicationType,
        databaseType,
    });
    const jsonEntities = entitiesPerApplicationMap.get(applicationName);
    return exportJSONEntities(jsonEntities, configuration);
}
function importOneApplicationAndEntities(jdlObject, configuration) {
    const importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    const formattedApplication = formatApplicationToExport(jdlObject.getApplications()[0], configuration);
    importState.exportedApplications.push(formattedApplication);
    const jdlApplication = jdlObject.getApplications()[0];
    const applicationName = jdlApplication.getConfigurationOptionValue(BASE_NAME);
    const entitiesPerApplicationMap = convert({
        jdlObject,
    });
    const jsonEntities = entitiesPerApplicationMap.get(applicationName);
    const { 'generator-begcode': config, ...remaining } = formattedApplication;
    importState.exportedApplicationsWithEntities[applicationName] = {
        config,
        ...remaining,
        entities: [],
    };
    if (jsonEntities.length !== 0) {
        const exportedJSONEntities = exportJSONEntities(jsonEntities, {
            applicationName,
            applicationType: jdlApplication.getConfigurationOptionValue(APPLICATION_TYPE),
            forSeveralApplications: false,
        });
        importState.exportedApplicationsWithEntities[applicationName].entities = exportedJSONEntities;
        importState.exportedEntities = uniqBy([...importState.exportedEntities, ...exportedJSONEntities], 'name');
    }
    return importState;
}
function importApplicationsAndEntities(jdlObject, configuration) {
    const importState = {
        exportedApplications: [],
        exportedApplicationsWithEntities: {},
        exportedEntities: [],
        exportedDeployments: [],
    };
    const formattedApplications = formatApplicationsToExport(jdlObject.applications, configuration);
    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),
            forSeveralApplications: true,
        });
        const exportedConfig = importState.exportedApplications.find(config => applicationName === config['generator-begcode'].baseName);
        const { 'generator-begcode': 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.applicationType;
    if (configuration.application) {
        baseName = configuration.application['generator-begcode'].baseName;
        applicationType = configuration.application['generator-begcode'].applicationType;
    }
    return exportEntities({
        entities,
        application: {
            name: baseName,
            type: applicationType,
            forSeveralApplications: !!configuration.forSeveralApplications,
        },
    });
}
