/**
 * 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 chalk from 'chalk';
import { isFileStateModified } from 'mem-fs-editor/state';
import { clientFrameworkTypes, fieldTypes } from "../../lib/jhipster/index.js";
import { upperFirstCamelCase } from "../../lib/utils/index.js";
import { createNeedleCallback } from "../base-core/support/index.js";
import { ClientApplicationGenerator } from "../client/generator.js";
import { generateEntityClientEnumImports as getClientEnumImportsFormat, generateEntityClientFields as getHydratedEntityClientFields, generateEntityClientImports as formatEntityClientImports, } from "../client/support/index.js";
import { JAVA_WEBAPP_SOURCES_DIR } from "../index.js";
import cleanupOldFilesTask from "./cleanup.js";
import { cleanupEntitiesFiles, postWriteEntitiesFiles, writeEntitiesFiles } from "./entity-files-react.js";
import { writeFiles } from "./files-react.js";
import { isTranslatedReactFile, translateReactFilesTransform } from "./support/index.js";
const { CommonDBTypes } = fieldTypes;
const TYPE_BOOLEAN = CommonDBTypes.BOOLEAN;
const { REACT } = clientFrameworkTypes;
export default class ReactGenerator extends ClientApplicationGenerator {
    constructor(args, options, features) {
        super(args, options, { ...features, loadCommand: ['jhipster:server'] });
    }
    async beforeQueue() {
        if (!this.fromBlueprint) {
            await this.composeWithBlueprints();
        }
        await this.dependsOnBootstrap('react');
        if (!this.delegateToBlueprint) {
            await this.dependsOnJHipster('jhipster:client:i18n');
            await this.dependsOnJHipster('client');
            await this.dependsOnJHipster('languages');
        }
    }
    get composing() {
        return this.asComposingTaskGroup({
            async composing() {
                await this.composeWithJHipster('jhipster:javascript-simple-application:eslint');
                await this.composeWithJHipster('jhipster:client:common');
                if (this.jhipsterConfigWithDefaults.websocket === 'spring-websocket') {
                    await this.composeWithJHipster('jhipster:client:encode-csrf-token');
                }
            },
        });
    }
    get [ClientApplicationGenerator.COMPOSING]() {
        return this.delegateTasksToBlueprint(() => this.composing);
    }
    get preparing() {
        return this.asPreparingTaskGroup({
            loadPackageJson({ application }) {
                this.loadNodeDependenciesFromPackageJson(application.nodeDependencies, this.fetchFromInstalledJHipster('react', 'resources', 'package.json'));
            },
            applicationDefaults({ application, applicationDefaults }) {
                application.prettierExtensions.push('html', 'tsx', 'css', 'scss');
                if (application.clientBundlerWebpack) {
                    application.prettierFolders.push('webpack/');
                }
                if (!application.backendTypeJavaAny && application.clientSrcDir !== JAVA_WEBAPP_SOURCES_DIR) {
                    // When we have a java backend, 'src/**' is already added by java:bootstrap
                    application.prettierFolders.push(`${application.clientSrcDir}**/`);
                }
                applicationDefaults({
                    __override__: true,
                    webappEnumerationsDir: app => `${app.clientSrcDir}app/shared/model/enumerations/`,
                });
            },
            async javaNodeBuildPaths({ application }) {
                const { clientBundlerWebpack, javaNodeBuildPaths } = application;
                javaNodeBuildPaths?.push('.postcss.config.js', 'tsconfig.json', 'vite.config.ts', 'vitest.config.ts');
                if (clientBundlerWebpack) {
                    javaNodeBuildPaths?.push('webpack/');
                }
            },
            prepareForTemplates({ application, source }) {
                source.addWebpackConfig = args => {
                    const webpackPath = `${application.clientRootDir}webpack/webpack.common.js`;
                    const ignoreNonExisting = this.ignoreNeedlesError && 'Webpack configuration file not found';
                    this.editFile(webpackPath, { ignoreNonExisting }, createNeedleCallback({
                        needle: 'jhipster-needle-add-webpack-config',
                        contentToAdd: `,${args.config}`,
                    }));
                };
                source.addClientStyle = ({ style, comment }) => {
                    comment =
                        comment ?
                            `/* ==========================================================================
${comment}
========================================================================== */
`
                            : '';
                    this.editFile(`${application.clientSrcDir}app/app.scss`, createNeedleCallback({
                        needle: 'scss-add-main',
                        contentToAdd: `${comment}${style}`,
                        contentToCheck: style,
                    }));
                };
                source.addEntitiesToClient = ({ application, entities }) => {
                    const entityRoutes = `${application.clientSrcDir}app/entities/routes.tsx`;
                    const entityReducers = `${application.clientSrcDir}app/entities/reducers.ts`;
                    const entityMenu = `${application.clientSrcDir}app/entities/menu.tsx`;
                    for (const entity of entities) {
                        const { entityAngularName, entityInstance, entityFolderName, entityFileName, entityPage, entityUrl, entityTranslationKeyMenuPath, entityNameHumanized, } = entity;
                        this.editFile(entityMenu, createNeedleCallback({
                            needle: 'add-entity-to-menu',
                            contentToAdd: `<MenuItem icon="asterisk" to="/${entityPage}">
  ${application.enableTranslation ? `<Translate contentKey="${entityTranslationKeyMenuPath}" />` : entityNameHumanized}
</MenuItem>`,
                        }));
                        this.editFile(entityRoutes, createNeedleCallback({
                            needle: 'add-route-import',
                            contentToAdd: `import ${entityAngularName} from './${entityFolderName}';`,
                        }), createNeedleCallback({
                            needle: 'add-route-path',
                            contentToAdd: `<Route path="/${entityUrl}/*" element={<${entityAngularName} />} />`,
                        }));
                        this.editFile(entityReducers, createNeedleCallback({
                            needle: 'add-reducer-import',
                            contentToAdd: `import ${entityInstance} from 'app/entities/${entityFolderName}/${entityFileName}.reducer';`,
                        }), createNeedleCallback({
                            needle: 'add-reducer-combine',
                            contentToAdd: `${entityInstance},`,
                        }));
                    }
                };
            },
        });
    }
    get [ClientApplicationGenerator.PREPARING]() {
        return this.delegateTasksToBlueprint(() => this.preparing);
    }
    get preparingEachEntity() {
        return this.asPreparingEachEntityTaskGroup({
            react({ application, entity }) {
                entity.entityReactState =
                    application.applicationTypeMonolith ? entity.entityInstance : `${application.lowercaseBaseName}.${entity.entityInstance}`;
            },
        });
    }
    get [ClientApplicationGenerator.PREPARING_EACH_ENTITY]() {
        return this.delegateTasksToBlueprint(() => this.preparingEachEntity);
    }
    get preparingEachEntityField() {
        return this.asPreparingEachEntityFieldTaskGroup({
            react({ field }) {
                field.fieldValidateRulesPatternReact ??= field.fieldValidateRulesPattern?.replace(/'/g, String.raw `\'`);
            },
        });
    }
    get [ClientApplicationGenerator.PREPARING_EACH_ENTITY_FIELD]() {
        return this.delegateTasksToBlueprint(() => this.preparingEachEntityField);
    }
    get default() {
        return this.asDefaultTaskGroup({
            queueTranslateTransform({ application }) {
                if (!application.enableTranslation) {
                    this.queueTransformStream({
                        name: 'translating react application',
                        filter: file => isFileStateModified(file) && file.path.startsWith(this.destinationPath()) && isTranslatedReactFile(file),
                        refresh: false,
                    }, translateReactFilesTransform(application.getWebappTranslation));
                }
            },
        });
    }
    get [ClientApplicationGenerator.DEFAULT]() {
        return this.delegateTasksToBlueprint(() => this.default);
    }
    get writing() {
        return this.asWritingTaskGroup({
            async cleanup({ control }) {
                await control.cleanupFiles({
                    '9.0.0-alpha.0': [
                        // Try to remove possibles old eslint config files
                        'eslint.config.js',
                        'eslint.config.mjs',
                        'postcss.config.js',
                    ],
                });
            },
            cleanupOldFilesTask,
            writeFiles,
        });
    }
    get [ClientApplicationGenerator.WRITING]() {
        return this.delegateTasksToBlueprint(() => this.writing);
    }
    get writingEntities() {
        return {
            cleanupEntitiesFiles,
            writeEntitiesFiles,
        };
    }
    get [ClientApplicationGenerator.WRITING_ENTITIES]() {
        return this.delegateTasksToBlueprint(() => this.writingEntities);
    }
    get postWriting() {
        return this.asPostWritingTaskGroup({
            addMicrofrontendDependencies({ application, source }) {
                if (!application.microfrontend)
                    return;
                source.mergeClientPackageJson({
                    devDependencies: { '@module-federation/enhanced': null },
                });
            },
            addWebsocketDependencies({ application, source }) {
                const { communicationSpringWebsocket, nodeDependencies } = application;
                if (communicationSpringWebsocket) {
                    source.mergeClientPackageJson({
                        dependencies: {
                            rxjs: nodeDependencies.rxjs,
                            'sockjs-client': nodeDependencies['sockjs-client'],
                            'webstomp-client': nodeDependencies['webstomp-client'],
                        },
                    });
                }
            },
            sonar({ application, source }) {
                const { clientI18nDir, clientDistDir, clientSrcDir, temporaryDir } = application;
                source.addSonarProperties?.([
                    { key: 'sonar.test.inclusions', value: `${clientSrcDir}app/**/*.spec.ts, ${clientSrcDir}app/**/*.spec.tsx`, valueSep: ', ' },
                    { key: 'sonar.testExecutionReportPaths', value: `${temporaryDir}test-results/jest/TESTS-results-vitest.xml` },
                    { key: 'sonar.javascript.lcov.reportPaths', value: `${temporaryDir}test-results/lcov-report/lcov.info` },
                    {
                        key: 'sonar.exclusions',
                        value: `${clientSrcDir}content/**/*.*, ${clientI18nDir}*.ts, ${clientDistDir}**/*.*`,
                        valueSep: ', ',
                    },
                ]);
            },
        });
    }
    get [ClientApplicationGenerator.POST_WRITING]() {
        return this.delegateTasksToBlueprint(() => this.postWriting);
    }
    get postWritingEntities() {
        return {
            postWriteEntitiesFiles,
        };
    }
    get [ClientApplicationGenerator.POST_WRITING_ENTITIES]() {
        return this.delegateTasksToBlueprint(() => this.postWritingEntities);
    }
    get end() {
        return this.asEndTaskGroup({
            end({ application }) {
                this.log.ok(`React ${application.nodeDependencies.react} application generated successfully.`);
                this.log.log(chalk.green(`  Start your Webpack development server with:
  ${chalk.yellow.bold(`${application.nodePackageManager} start`)}
`));
            },
        });
    }
    get [ClientApplicationGenerator.END]() {
        return this.delegateTasksToBlueprint(() => this.end);
    }
    /**
     * @private
     * Generate Entity Client Field Default Values
     */
    generateEntityClientFieldDefaultValues(fields) {
        const defaultVariablesValues = {};
        fields.forEach(field => {
            const { fieldType, fieldName } = field;
            if (fieldType === TYPE_BOOLEAN) {
                defaultVariablesValues[fieldName] = `${fieldName}: false,`;
            }
        });
        return defaultVariablesValues;
    }
    generateEntityClientFields(primaryKey, fields, relationships, dto, customDateType, embedded = false) {
        return getHydratedEntityClientFields(primaryKey, fields, relationships, dto, customDateType, embedded, REACT);
    }
    generateEntityClientImports(relationships, dto) {
        return formatEntityClientImports(relationships, dto, REACT);
    }
    generateEntityClientEnumImports(fields) {
        return getClientEnumImportsFormat(fields, REACT);
    }
    /**
     * get the an upperFirst camelCase value.
     * @param {string} value string to convert
     */
    upperFirstCamelCase(value) {
        return upperFirstCamelCase(value);
    }
}
