import { readdir } from 'fs/promises';
import { existsSync } from 'fs';
import chalk from 'chalk';
import BaseGenerator from '../base/index.js';
import { YO_RC_FILE } from '../generator-constants.js';
import { GENERATOR_BOOTSTRAP_APPLICATION } from '../generator-list.js';
import { normalizePathEnd } from '../base/support/path.js';
import { CUSTOM_PRIORITIES, PRIORITY_NAMES } from './priorities.js';
import command from './command.js';
const { PROMPTING_WORKSPACES, CONFIGURING_WORKSPACES, LOADING_WORKSPACES, PREPARING_WORKSPACES, DEFAULT, WRITING, POST_WRITING, PRE_CONFLICTS, INSTALL, END, } = PRIORITY_NAMES;
export default class BaseWorkspacesGenerator extends BaseGenerator {
    static PROMPTING_WORKSPACES = BaseGenerator.asPriority(PROMPTING_WORKSPACES);
    static CONFIGURING_WORKSPACES = BaseGenerator.asPriority(CONFIGURING_WORKSPACES);
    static LOADING_WORKSPACES = BaseGenerator.asPriority(LOADING_WORKSPACES);
    static PREPARING_WORKSPACES = BaseGenerator.asPriority(PREPARING_WORKSPACES);
    appsFolders;
    directoryPath;
    constructor(args, options, features) {
        super(args, options, features);
        if (!this.options.help) {
            this.registerPriorities(CUSTOM_PRIORITIES);
            this.parseJHipsterOptions(command.options);
        }
    }
    loadWorkspacesConfig(opts) {
        const { context = this } = opts ?? {};
        context.appsFolders = this.jhipsterConfig.appsFolders;
        context.directoryPath = this.jhipsterConfig.directoryPath ?? './';
    }
    configureWorkspacesConfig() {
        this.jhipsterConfig.directoryPath = normalizePathEnd(this.jhipsterConfig.directoryPath ?? './');
    }
    async askForWorkspacesConfig() {
        let appsFolders;
        await this.prompt([
            {
                type: 'input',
                name: 'directoryPath',
                message: 'Enter the root directory where your applications are located',
                default: '../',
                validate: async (input) => {
                    const path = this.destinationPath(input);
                    if (existsSync(path)) {
                        const applications = await this.findApplicationFolders(path);
                        return applications.length === 0 ? `No application found in ${path}` : true;
                    }
                    return `${path} is not a directory or doesn't exist`;
                },
            },
            {
                type: 'checkbox',
                name: 'appsFolders',
                when: async (answers) => {
                    const directoryPath = answers.directoryPath;
                    appsFolders = (await this.findApplicationFolders(directoryPath)).filter(app => app !== 'jhipster-registry' && app !== 'registry');
                    this.log.log(chalk.green(`${appsFolders.length} applications found at ${this.destinationPath(directoryPath)}\n`));
                    return true;
                },
                message: 'Which applications do you want to include in your configuration?',
                choices: () => appsFolders,
                default: () => appsFolders,
                validate: input => (input.length === 0 ? 'Please choose at least one application' : true),
            },
        ], this.config);
    }
    async findApplicationFolders(directoryPath = this.directoryPath ?? '.') {
        return (await readdir(this.destinationPath(directoryPath), { withFileTypes: true }))
            .filter(dirent => dirent.isDirectory())
            .map(dirent => dirent.name)
            .filter(folder => existsSync(this.destinationPath(directoryPath, folder, 'package.json')) &&
            existsSync(this.destinationPath(directoryPath, folder, YO_RC_FILE)));
    }
    async resolveApplicationFolders({ directoryPath = this.directoryPath, appsFolders = this.appsFolders ?? [], } = {}) {
        return Object.fromEntries(appsFolders.map(appFolder => [appFolder, this.destinationPath(directoryPath ?? '.', appFolder)]));
    }
    async bootstrapApplications() {
        const resolvedApplicationFolders = await this.resolveApplicationFolders();
        for (const [_appFolder, resolvedFolder] of Object.entries(resolvedApplicationFolders)) {
            await this.composeWithJHipster(GENERATOR_BOOTSTRAP_APPLICATION, {
                generatorOptions: { destinationRoot: resolvedFolder, reproducible: true },
            });
        }
        this.getSharedApplication(this.destinationPath()).workspacesApplications = Object.entries(resolvedApplicationFolders).map(([appFolder, resolvedFolder], index) => {
            const application = this.getSharedApplication(resolvedFolder)?.sharedApplication;
            application.appFolder = appFolder;
            application.composePort = 8080 + index;
            return application;
        });
    }
    getArgsForPriority(priorityName) {
        const args = super.getArgsForPriority(priorityName);
        if (![
            PROMPTING_WORKSPACES,
            CONFIGURING_WORKSPACES,
            LOADING_WORKSPACES,
            PREPARING_WORKSPACES,
            DEFAULT,
            WRITING,
            POST_WRITING,
            PRE_CONFLICTS,
            INSTALL,
            END,
        ].includes(priorityName)) {
            return args;
        }
        const [first, ...others] = args ?? [];
        const sharedData = this.getSharedApplication(this.destinationPath());
        const deployment = sharedData.sharedDeployment;
        const workspaces = sharedData.sharedWorkspaces;
        const applications = sharedData.workspacesApplications;
        return [
            {
                ...first,
                workspaces,
                deployment,
                applications,
            },
            ...others,
        ];
    }
}
