/**
 * 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 { createNeedleCallback } from "../../../base-core/support/needles.js";
import { GRADLE_BUILD_SRC_MAIN_DIR, SERVER_MAIN_SRC_DIR, SERVER_TEST_SRC_DIR } from "../../../generator-constants.js";
import { moveToJavaPackageSrcDir, moveToJavaPackageTestDir } from "../../../java/support/files.js";
import { SpringBootApplicationGenerator } from "../../generator.js";
import { getCacheProviderJavaDefinition } from "./internal/dependencies.js";
export default class SpringCacheGenerator extends SpringBootApplicationGenerator {
    async beforeQueue() {
        if (!this.fromBlueprint) {
            await this.composeWithBlueprints();
        }
        if (!this.delegateToBlueprint) {
            await this.dependsOnBootstrap('spring-boot');
        }
    }
    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 [SpringBootApplicationGenerator.CONFIGURING]() {
        return this.delegateTasksToBlueprint(() => this.configuring);
    }
    get preparing() {
        return this.asPreparingTaskGroup({
            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 {
                    // Add noop
                    source.addEntryToCache = () => { };
                    // Add noop
                    source.addEntityToCache = () => { };
                }
            },
        });
    }
    get [SpringBootApplicationGenerator.PREPARING]() {
        return this.delegateTasksToBlueprint(() => this.preparing);
    }
    get writing() {
        return this.asWritingTaskGroup({
            async cleanup({ application, control }) {
                if (application.cacheProviderHazelcast) {
                    if (control.isJhipsterVersionLessThan('3.12.0')) {
                        this.removeFile(`${application.javaPackageSrcDir}config/hazelcast/HazelcastCacheRegionFactory.java`);
                        this.removeFile(`${application.javaPackageSrcDir}config/hazelcast/package-info.java`);
                    }
                }
                if (application.cacheProviderRedis) {
                    if (control.isJhipsterVersionLessThan('7.8.2')) {
                        this.removeFile(`${application.javaPackageTestDir}RedisTestContainerExtension.java`);
                    }
                }
                if (application.buildToolGradle) {
                    if (control.isJhipsterVersionLessThan('8.1.1')) {
                        this.removeFile('gradle/cache.gradle');
                    }
                }
                await control.cleanupFiles({
                    '8.9.1': [[application.cacheProviderInfinispan, `${application.javaPackageSrcDir}config/CacheFactoryConfiguration.java`]],
                    '9.0.0-alpha.0': [`${GRADLE_BUILD_SRC_MAIN_DIR}/jhipster.spring-cache-conventions.gradle`],
                    '9.0.0-beta.1': [
                        [
                            application.cacheProviderRedis,
                            `${application.javaPackageSrcDir}config/RedisTestContainersSpringContextCustomizerFactory.java`,
                            `${application.javaPackageSrcDir}config/EmbeddedRedis.java`,
                            `${application.srcTestResources}META-INF/spring.factories`,
                        ],
                    ],
                });
            },
            async writeTask({ application }) {
                await this.writeFiles({
                    sections: {
                        cacheFiles: [
                            {
                                path: `${SERVER_MAIN_SRC_DIR}_package_/`,
                                renameTo: moveToJavaPackageSrcDir,
                                templates: ['config/CacheKeyGeneratorConfiguration.java'],
                            },
                            {
                                path: `${SERVER_MAIN_SRC_DIR}_package_/`,
                                renameTo: moveToJavaPackageSrcDir,
                                templates: [`config/CacheConfiguration_${application.cacheProvider}.java`],
                            },
                            {
                                condition: () => application.cacheProviderRedis,
                                path: `${SERVER_TEST_SRC_DIR}_package_/`,
                                renameTo: moveToJavaPackageTestDir,
                                templates: ['config/RedisTestContainer.java'],
                            },
                        ],
                    },
                    context: application,
                });
            },
        });
    }
    get [SpringBootApplicationGenerator.WRITING]() {
        return this.delegateTasksToBlueprint(() => this.writing);
    }
    get postWriting() {
        return this.asPostWritingTaskGroup({
            dependencies({ application, source }) {
                if (application.cacheProviderInfinispan) {
                    source.overrideProperty({ property: 'infinispan.version', value: application.javaDependencies.infinispan });
                }
            },
            applyGradleScript({ source, application }) {
                if (application.buildToolGradle) {
                    if (application.cacheProviderCaffeine) {
                        source.addGradleDependencyCatalogVersion?.({ name: 'typesafe', version: application.javaDependencies?.typesafe });
                        source.addGradleBuildSrcDependencyCatalogVersion?.({ name: 'typesafe', version: application.javaDependencies?.typesafe });
                    }
                    if (application.cacheProviderHazelcast) {
                        source.addGradleDependencyCatalogVersion?.({
                            name: 'hazelcast-spring',
                            version: application.javaDependencies?.['hazelcast-spring'],
                        });
                        source.addGradleBuildSrcDependencyCatalogVersion?.({
                            name: 'hazelcast-spring',
                            version: application.javaDependencies?.['hazelcast-spring'],
                        });
                        if (application.enableHibernateCache) {
                            source.addGradleDependencyCatalogVersion?.({
                                name: 'hazelcast-hibernate53',
                                version: application.javaDependencies?.['hazelcast-hibernate53'],
                            });
                            source.addGradleBuildSrcDependencyCatalogVersion?.({
                                name: 'hazelcast-hibernate53',
                                version: application.javaDependencies?.['hazelcast-hibernate53'],
                            });
                        }
                    }
                }
            },
            addDependencies({ application, source }) {
                if (!application.javaDependencies) {
                    throw new Error('Some application fields are be mandatory');
                }
                const { javaDependencies, cacheProvider, enableHibernateCache, springBoot4 } = application;
                const definition = getCacheProviderJavaDefinition(cacheProvider, javaDependencies, { springBoot4 });
                source.addJavaDefinitions?.({
                    ...definition.base,
                    dependencies: [
                        { groupId: 'org.springframework.boot', artifactId: 'spring-boot-starter-cache' },
                        ...definition.base.dependencies,
                    ],
                }, {
                    condition: Boolean(enableHibernateCache && definition.hibernateCache),
                    ...definition.hibernateCache,
                });
                if (application.cacheProviderRedis) {
                    source.addSpringBootModule('spring-boot-testcontainers');
                }
            },
            integrationTest({ application, source }) {
                if (application.cacheProviderRedis) {
                    source.editJavaFile(`${application.javaPackageTestDir}IntegrationTest.java`, {
                        imports: [`${application.packageName}.config.RedisTestContainer`],
                        annotations: [
                            {
                                package: 'org.springframework.boot.testcontainers.context',
                                annotation: 'ImportTestcontainers',
                                parameters: (_, cb) => cb.addKeyValue('value', 'RedisTestContainer.class'),
                            },
                        ],
                    });
                }
                else if (application.cacheProviderInfinispan) {
                    source.editJavaFile(`${application.javaPackageTestDir}IntegrationTest.java`, {
                        imports: ['org.springframework.boot.autoconfigure.cache.CacheType'],
                        annotations: [
                            {
                                package: 'org.springframework.boot.cache.test.autoconfigure',
                                annotation: 'AutoConfigureCache',
                                parameters: (_, cb) => cb.addKeyValue('cacheProvider', 'CacheType.INFINISPAN'),
                            },
                        ],
                    });
                }
            },
            sonar({ application, source }) {
                source.ignoreSonarRule?.({
                    ruleId: 'S1192',
                    resourceKey: `${application.javaPackageSrcDir}config/CacheConfiguration.java`,
                    ruleKey: 'java:S1192',
                    comment: 'Rule https://rules.sonarsource.com/java/RSPEC-1192, there is no easy way to avoid this issue',
                });
            },
        });
    }
    get [SpringBootApplicationGenerator.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.builtInUser)) {
                        source.addEntityToCache?.({
                            entityAbsoluteClass: entity.entityAbsoluteClass,
                            relationships: entity.relationships,
                        });
                    }
                }
            },
        });
    }
    get [SpringBootApplicationGenerator.POST_WRITING_ENTITIES]() {
        return this.delegateTasksToBlueprint(() => this.postWritingEntities);
    }
}
