import assert from 'assert/strict';
import BaseApplicationGenerator from '../base-application/index.js';
import { GRADLE_BUILD_SRC_DIR } from '../generator-constants.js';
import { mutateData } from '../../lib/utils/object.js';
import { QUEUES } from '../base/priorities.js';
import files from './files.js';
import { GRADLE } from './constants.js';
import cleanupOldServerFilesTask from './cleanup.js';
import { addGradleDependenciesCallback, addGradleDependenciesCatalogVersionCallback, addGradleDependencyCatalogLibrariesCallback, addGradleDependencyCatalogPluginsCallback, addGradleMavenRepositoryCallback, addGradlePluginCallback, addGradlePluginFromCatalogCallback, addGradlePluginManagementCallback, addGradlePropertyCallback, applyFromGradleCallback, gradleNeedleOptionsWithDefaults, sortDependencies, } from './internal/needles.js';
const { PRE_CONFLICTS_QUEUE } = QUEUES;
export default class GradleGenerator extends BaseApplicationGenerator {
    gradleVersionFromWrapper;
    async beforeQueue() {
        if (!this.fromBlueprint) {
            await this.composeWithBlueprints();
        }
        if (!this.delegateToBlueprint) {
            await this.dependsOnBootstrapApplicationServer();
        }
    }
    get configuring() {
        return this.asConfiguringTaskGroup({
            configure() {
                if (this.jhipsterConfigWithDefaults.buildTool !== GRADLE) {
                    this.config.defaults({
                        buildTool: GRADLE,
                    });
                }
            },
        });
    }
    get [BaseApplicationGenerator.CONFIGURING]() {
        return this.delegateTasksToBlueprint(() => this.configuring);
    }
    get loading() {
        return this.asLoadingTaskGroup({
            loadGradleVersion({ application }) {
                const propFile = this.readTemplate(this.jhipsterTemplatePath('gradle/wrapper/gradle-wrapper.properties'));
                this.gradleVersionFromWrapper = propFile?.toString().match(/gradle-(\d+\.\d+(?:\.\d+)?)-/)?.[1];
                if (!this.gradleVersionFromWrapper) {
                    throw new Error('Could not determine Gradle version from gradle-wrapper.properties');
                }
                mutateData(application, {
                    gradleVersion: this.useVersionPlaceholders ? 'GRADLE_VERSION' : this.gradleVersionFromWrapper,
                });
            },
        });
    }
    get [BaseApplicationGenerator.LOADING]() {
        return this.delegateTasksToBlueprint(() => this.loading);
    }
    get preparing() {
        return this.asPreparingTaskGroup({
            async verify({ application }) {
                assert.equal(application.buildTool, GRADLE);
            },
            prepareConventionsPlugins({ application }) {
                application.gradleBuildSrc = GRADLE_BUILD_SRC_DIR;
            },
            addSourceNeddles({ application, source }) {
                const { gradleBuildSrc } = application;
                source.applyFromGradle = script => this.editFile('build.gradle', applyFromGradleCallback(script));
                source.addGradleDependencies = (dependencies, options = {}) => {
                    const { gradleFile } = gradleNeedleOptionsWithDefaults(options);
                    if (gradleFile === 'build.gradle') {
                        source._gradleDependencies = source._gradleDependencies ?? [];
                        source._gradleDependencies.push(...dependencies);
                        this.queueTask({
                            method: () => {
                                this.editFile(gradleFile, addGradleDependenciesCallback(source._gradleDependencies.sort(sortDependencies)));
                                source._gradleDependencies = [];
                            },
                            taskName: '_persiteGradleDependencies',
                            once: true,
                            queueName: PRE_CONFLICTS_QUEUE,
                        });
                        return;
                    }
                    dependencies = [...dependencies].sort(sortDependencies);
                    this.editFile(gradleFile, addGradleDependenciesCallback(dependencies));
                };
                source.addGradleDependency = (dependency, options) => source.addGradleDependencies([dependency], options);
                source.addGradlePlugin = plugin => this.editFile('build.gradle', addGradlePluginCallback(plugin));
                source.addGradleMavenRepository = repository => this.editFile('build.gradle', addGradleMavenRepositoryCallback(repository));
                source.addGradlePluginManagement = plugin => this.editFile('settings.gradle', addGradlePluginManagementCallback(plugin));
                source.addGradleProperty = property => {
                    application.javaProperties[property.property] = property.value;
                    this.editFile('gradle.properties', addGradlePropertyCallback(property));
                };
                source.addGradleDependencyCatalogVersions = (versions, { gradleVersionCatalogFile = 'gradle/libs.versions.toml' } = {}) => this.editFile(gradleVersionCatalogFile, addGradleDependenciesCatalogVersionCallback(versions));
                source.addGradleDependencyCatalogVersion = (version, options) => source.addGradleDependencyCatalogVersions([version], options);
                source.addGradleDependencyCatalogLibraries = (libs, options = {}) => {
                    const { gradleFile, gradleVersionCatalogFile } = gradleNeedleOptionsWithDefaults(options);
                    libs = [...libs].sort((a, b) => a.libraryName.localeCompare(b.libraryName));
                    this.editFile(gradleVersionCatalogFile, addGradleDependencyCatalogLibrariesCallback(libs));
                    source.addGradleDependencies(libs.filter(lib => lib.scope), { gradleFile });
                };
                source.addGradleDependencyCatalogLibrary = (lib, options) => source.addGradleDependencyCatalogLibraries([lib], options);
                source.addGradleDependencyCatalogPlugins = plugins => {
                    this.editFile('gradle/libs.versions.toml', addGradleDependencyCatalogPluginsCallback(plugins));
                    this.editFile('build.gradle', addGradlePluginFromCatalogCallback(plugins));
                };
                source.addGradleDependencyCatalogPlugin = plugin => source.addGradleDependencyCatalogPlugins([plugin]);
                source.addGradleBuildSrcDependency = dependency => source.addGradleDependencies([dependency], { gradleFile: `${gradleBuildSrc}/build.gradle` });
                source.addGradleBuildSrcDependencyCatalogVersion = version => source.addGradleDependencyCatalogVersions([version], {
                    gradleVersionCatalogFile: `${gradleBuildSrc}/gradle/libs.versions.toml`,
                });
                source.addGradleBuildSrcDependencyCatalogVersions = versions => source.addGradleDependencyCatalogVersions(versions);
                source.addGradleBuildSrcDependencyCatalogLibraries = libs => source.addGradleDependencyCatalogLibraries(libs, {
                    gradleFile: `${gradleBuildSrc}/build.gradle`,
                    gradleVersionCatalogFile: `${gradleBuildSrc}/gradle/libs.versions.toml`,
                });
            },
        });
    }
    get [BaseApplicationGenerator.PREPARING]() {
        return this.delegateTasksToBlueprint(() => this.preparing);
    }
    get writing() {
        return this.asWritingTaskGroup({
            cleanupOldServerFilesTask,
            async writeFiles({ application }) {
                await this.writeFiles({ sections: files, context: application });
            },
        });
    }
    get [BaseApplicationGenerator.WRITING]() {
        return this.delegateTasksToBlueprint(() => this.writing);
    }
    get postWriting() {
        return this.asPostWritingTaskGroup({
            updateGradleVersion({ application }) {
                const { gradleVersion } = application;
                if (gradleVersion !== this.gradleVersionFromWrapper) {
                    this.editFile('gradle/wrapper/gradle-wrapper.properties', content => content.replace(`-${this.gradleVersionFromWrapper}-`, `-${gradleVersion}-`));
                }
            },
        });
    }
    get [BaseApplicationGenerator.POST_WRITING]() {
        return this.delegateTasksToBlueprint(() => this.postWriting);
    }
}
