import BaseApplicationGenerator from '../base-application/index.js';
import { createNeedleCallback } from '../base/support/needles.js';
import writeTask from './files.js';
import cleanupTask from './cleanup.js';
import { getCacheProviderMavenDefinition } from './internal/dependencies.js';
export default class SpringCacheGenerator extends BaseApplicationGenerator {
    async beforeQueue() {
        if (!this.fromBlueprint) {
            await this.composeWithBlueprints();
        }
        if (!this.delegateToBlueprint) {
            await this.dependsOnBootstrapApplication();
        }
    }
    get configuring() {
        return this.asConfiguringTaskGroup({
            configure() {
                const { databaseType, reactive, cacheProvider } = this.jhipsterConfigWithDefaults;
                if (this.jhipsterConfig.enableHibernateCache && (reactive || databaseType !== 'sql')) {
                    this.log.verboseInfo(`Disabling hibernate cache for ${reactive ? 'reactive application' : 'non-SQL databases'}`);
                    this.jhipsterConfig.enableHibernateCache = undefined;
                }
                if (reactive && cacheProvider !== 'no') {
                    this.log.error(`Cache provider is not supported in reactive application`);
                }
            },
        });
    }
    get [BaseApplicationGenerator.CONFIGURING]() {
        return this.delegateTasksToBlueprint(() => this.configuring);
    }
    get preparing() {
        return this.asPreparingTaskGroup({
            cancel() {
                if (this.jhipsterConfigWithDefaults.cacheProvider === 'no') {
                    this.cancelCancellableTasks();
                }
            },
            loadDependabot({ application }) {
                this.loadJavaDependenciesFromGradleCatalog(application.javaDependencies, true);
            },
            addNeedles({ source, application }) {
                if (application.cacheProviderEhcache || application.cacheProviderCaffeine || application.cacheProviderRedis) {
                    const cacheConfigurationFile = `${application.javaPackageSrcDir}config/CacheConfiguration.java`;
                    const needle = `${application.cacheProvider}-add-entry`;
                    const useJcacheConfiguration = application.cacheProviderRedis;
                    const addEntryToCacheCallback = entry => createNeedleCallback({
                        needle,
                        contentToAdd: `createCache(cm, ${entry}${useJcacheConfiguration ? ', jcacheConfiguration' : ''});`,
                    });
                    source.addEntryToCache = ({ entry }) => this.editFile(cacheConfigurationFile, addEntryToCacheCallback(entry));
                    source.addEntityToCache = ({ entityAbsoluteClass, relationships }) => {
                        const entry = `${entityAbsoluteClass}.class.getName()`;
                        this.editFile(cacheConfigurationFile, addEntryToCacheCallback(entry), ...(relationships ?? [])
                            .filter(rel => rel.collection)
                            .map(rel => addEntryToCacheCallback(`${entry} + ".${rel.propertyName}"`)));
                    };
                }
                else {
                    source.addEntryToCache = () => { };
                    source.addEntityToCache = () => { };
                }
            },
        });
    }
    get [BaseApplicationGenerator.PREPARING]() {
        return this.delegateTasksToBlueprint(() => this.preparing);
    }
    get writing() {
        return this.asWritingTaskGroup({
            cleanupTask,
            writeTask,
        });
    }
    get [BaseApplicationGenerator.WRITING]() {
        return this.delegateTasksToBlueprint(() => this.writing);
    }
    get postWriting() {
        return this.asPostWritingTaskGroup({
            addTestSpringFactory({ source, application }) {
                if (application.cacheProviderRedis) {
                    source.addTestSpringFactory?.({
                        key: 'org.springframework.test.context.ContextCustomizerFactory',
                        value: `${application.packageName}.config.RedisTestContainersSpringContextCustomizerFactory`,
                    });
                }
            },
            applyGradleScript({ source, application }) {
                if (application.buildToolGradle) {
                    const applicationAny = application;
                    if (applicationAny.cacheProviderCaffeine) {
                        source.addGradleDependencyCatalogVersion?.({ name: 'typesafe', version: application.javaDependencies?.typesafe });
                        source.addGradleBuildSrcDependencyCatalogVersion?.({ name: 'typesafe', version: application.javaDependencies?.typesafe });
                    }
                    if (applicationAny.cacheProviderHazelcast) {
                        source.addGradleDependencyCatalogVersion?.({
                            name: 'hazelcast-spring',
                            version: application.javaDependencies?.['hazelcast-spring'],
                        });
                        source.addGradleBuildSrcDependencyCatalogVersion?.({
                            name: 'hazelcast-spring',
                            version: application.javaDependencies?.['hazelcast-spring'],
                        });
                        if (applicationAny.enableHibernateCache) {
                            source.addGradleDependencyCatalogVersion?.({
                                name: 'hazelcast-hibernate53',
                                version: application.javaDependencies?.['hazelcast-hibernate53'],
                            });
                            source.addGradleBuildSrcDependencyCatalogVersion?.({
                                name: 'hazelcast-hibernate53',
                                version: application.javaDependencies?.['hazelcast-hibernate53'],
                            });
                        }
                    }
                    source.addGradlePlugin?.({ id: 'jhipster.spring-cache-conventions' });
                }
            },
            addDependencies({ application, source }) {
                if (!application.javaDependencies) {
                    throw new Error('Some application fields are be mandatory');
                }
                const { javaDependencies } = application;
                const { cacheProvider, enableHibernateCache, ormTool } = application;
                const definition = getCacheProviderMavenDefinition(cacheProvider, javaDependencies, ormTool);
                source.addJavaDefinitions?.({ gradleFile: 'buildSrc/src/main/groovy/jhipster.spring-cache-conventions.gradle' }, {
                    ...definition.base,
                    dependencies: [
                        { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-cache' },
                        ...definition.base.dependencies,
                    ],
                }, {
                    condition: Boolean(enableHibernateCache && definition.hibernateCache),
                    ...definition.hibernateCache,
                });
            },
        });
    }
    get [BaseApplicationGenerator.POST_WRITING]() {
        return this.delegateTasksToBlueprint(() => this.postWriting);
    }
    get postWritingEntities() {
        return this.asPostWritingEntitiesTaskGroup({
            customizeFiles({ application, entities, source }) {
                if (application.databaseTypeSql) {
                    for (const entity of entities.filter(entity => !entity.skipServer && !entity.builtIn)) {
                        const relationships = [...(entity.relationships || [])];
                        if (entity.name?.toLowerCase() === 'user' && application.authenticationTypeSession) {
                            relationships.push({
                                collection: true,
                                propertyName: 'persistentTokens',
                                relationshipName: 'persistentTokens',
                                persistableRelationship: false,
                            });
                        }
                        source.addEntityToCache?.({
                            entityAbsoluteClass: entity.entityAbsoluteClass,
                            relationships,
                        });
                    }
                }
            },
        });
    }
    get [BaseApplicationGenerator.POST_WRITING_ENTITIES]() {
        return this.delegateTasksToBlueprint(() => this.postWritingEntities);
    }
}
