"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Prompter = void 0;
const types_1 = require("../types");
const property_1 = require("./property");
const cliter_config_1 = require("../config/cliter.config");
const common_1 = require("../functions/common");
const inquirer = require("inquirer");
const Table = require("cli-table3");
exports.Prompter = {
    async promptForLoadModule(boundedContextName, moduleName) {
        const questions = [];
        questions.push({
            name: 'boundedContextName',
            message: 'Input the name of bonded context where will be created your module',
            type: 'input',
            when: (answers) => {
                if (boundedContextName) {
                    answers.boundedContextName = boundedContextName;
                    return false;
                }
                return true;
            },
        }, {
            name: 'moduleName',
            message: 'Input the name of module',
            type: 'input',
            when: (answers) => {
                if (moduleName) {
                    answers.moduleName = moduleName;
                    return false;
                }
                return true;
            },
        });
        const response = await inquirer.prompt(questions);
        return {
            boundedContextName: response.boundedContextName.toKebabCase(),
            moduleName: response.moduleName.toKebabCase(),
        };
    },
    async promptForLoadBoundedContext(boundedContextName) {
        const questions = [];
        questions.push({
            name: 'boundedContextName',
            message: 'Input the name of bonded context where will be created your module',
            type: 'input',
            when: (answers) => {
                if (boundedContextName) {
                    answers.boundedContextName = boundedContextName;
                    return false;
                }
                return true;
            },
        });
        const response = await inquirer.prompt(questions);
        return {
            boundedContextName: response.boundedContextName.toKebabCase(),
        };
    },
    async promptForGenerateModule(boundedContextName, moduleName) {
        const questions = [];
        questions.push({
            name: 'boundedContextName',
            message: 'Input the name of bonded context where will be created your module',
            type: 'input',
            when: (answers) => {
                if (boundedContextName) {
                    answers.boundedContextName = boundedContextName;
                    return false;
                }
                return true;
            },
        }, {
            name: 'moduleName',
            message: 'Input the name of module',
            type: 'input',
            when: (answers) => {
                if (moduleName) {
                    answers.moduleName = moduleName;
                    return false;
                }
                return true;
            },
        }, {
            name: 'moduleNames',
            message: 'Input the plural of the module name in kebab case format',
            type: 'input',
        }, {
            name: 'hasOAuth',
            message: 'do you want to protect this module with OAuth?',
            type: 'confirm',
        });
        const response = await inquirer.prompt(questions);
        return {
            boundedContextName: response.boundedContextName.toKebabCase(),
            moduleName: response.moduleName.toKebabCase(),
            moduleNames: response.moduleNames.toKebabCase(),
            hasOAuth: response.hasOAuth,
            hasTenant: false,
        };
    },
    async promptForGenerateAggregate() {
        const questions = [];
        questions.push({
            name: 'hasValueObject',
            message: 'Do you want to define a property?',
            type: 'confirm',
        });
        return inquirer.prompt(questions);
    },
    async promptSelectOriginFileToManage(files) {
        const questions = [];
        questions.push({
            name: 'fileToManage',
            message: 'Select file to manage',
            type: 'list',
            choices: files,
        });
        return inquirer.prompt(questions);
    },
    async promptSelectManagementAction() {
        const questions = [];
        questions.push({
            name: 'compareAction',
            message: 'Select an action',
            type: 'list',
            choices: Object.values(cliter_config_1.cliterConfig.compareActions),
        });
        return inquirer.prompt(questions);
    },
    async promptManageOriginFiles() {
        const questions = [];
        questions.push({
            name: 'hasCompareOriginFile',
            message: 'Do you want to manage origin files?',
            type: 'confirm',
        });
        return inquirer.prompt(questions);
    },
    async promptDefineAggregateProperty(generateCommandState) {
        const questions = [];
        let name = '';
        questions.push({
            name: 'name',
            message: 'What\'s the name of property (type in camel case, example: dateAt)',
            type: 'input',
            validate: (input, answers) => {
                name = input;
                return true;
            },
        });
        // only if filed end with Id
        questions.push({
            name: 'relationship',
            message: 'What kind of relationship do you want to create?',
            type: 'list',
            choices: Object.values(types_1.SqlRelationship).filter(item => ['none', 'one-to-one', 'many-to-one'].includes(item)),
            when: (answers) => {
                if (answers.name.endsWith('Id')) {
                    answers.type = 'id';
                    answers.length = 36;
                    return true;
                }
                return false;
            },
        });
        questions.push({
            name: 'type',
            message: 'What\'s the type of property?',
            type: 'list',
            choices: Object.values(types_1.SqlType),
            when: (answers) => !answers.type,
        });
        questions.push({
            name: 'enumOptions',
            message: 'Set comma separated enumeration options, example: ONE,TWO,THREE,FOUR',
            type: 'input',
            when: (answers) => answers.type === types_1.SqlType.ENUM,
        });
        questions.push({
            name: 'relationship',
            message: 'What kind of relationship do you want to create?',
            type: 'list',
            choices: Object.values(types_1.SqlRelationship).filter(item => !['many-to-one'].includes(item)),
            when: (answers) => answers.type === types_1.SqlType.RELATIONSHIP,
        });
        questions.push({
            name: 'relationshipSingularName',
            message: 'The property name will be plural, type its singular (example: for cars type car)',
            type: 'input',
            when: (answers) => answers.relationship === types_1.SqlRelationship.ONE_TO_MANY ||
                answers.relationship === types_1.SqlRelationship.MANY_TO_MANY,
        });
        questions.push({
            name: 'relationshipAggregate',
            message: 'What is the aggregate which you want to relate this property? (example: AdminLang)',
            type: 'input',
            when: (answers) => answers.relationship === types_1.SqlRelationship.ONE_TO_ONE ||
                answers.relationship === types_1.SqlRelationship.MANY_TO_ONE ||
                answers.relationship === types_1.SqlRelationship.ONE_TO_MANY ||
                answers.relationship === types_1.SqlRelationship.MANY_TO_MANY,
        });
        questions.push({
            name: 'relationshipModulePath',
            message: 'Type path to module where to find the aggregate with which you want to relate this property? Type with format: bounded-context/module',
            type: 'input',
            when: (answers) => {
                if (answers.relationship === types_1.SqlRelationship.ONE_TO_MANY || (answers.relationship === types_1.SqlRelationship.ONE_TO_ONE && !answers.name.endsWith('Id')))
                    answers.type = answers.relationshipAggregate;
                if (answers.relationship === types_1.SqlRelationship.ONE_TO_ONE && answers.name.endsWith('Id')) {
                    answers.type = 'id';
                    answers.length = 36;
                }
                // by default all many to many relationship will be nullable
                if (answers.relationship === types_1.SqlRelationship.MANY_TO_MANY)
                    answers.nullable = true;
                return answers.relationship === types_1.SqlRelationship.ONE_TO_ONE || answers.relationship === types_1.SqlRelationship.MANY_TO_ONE || answers.relationship === types_1.SqlRelationship.ONE_TO_MANY || answers.relationship === types_1.SqlRelationship.MANY_TO_MANY;
            },
        });
        questions.push({
            name: 'hasPivotTable',
            message: () => `You want to create the pivot table of your many to many relationship with name: ${generateCommandState.schema.boundedContextName.toPascalCase()}${generateCommandState.schema.moduleNames.toPascalCase()}${name.toPascalCase()}?`,
            type: 'confirm',
            when: (answers) => {
                return answers.relationship === types_1.SqlRelationship.MANY_TO_MANY;
            },
        });
        questions.push({
            name: 'decimals',
            message: 'Set total digits and decimals comma separated, example: 10,2',
            type: 'input',
            when: (answers) => answers.type === types_1.SqlType.DECIMAL,
            filter: (answers) => answers.split(',').map(item => Number.parseInt(item.trim(), 10)),
        });
        questions.push({
            name: 'length',
            message: 'What\'s the length of property? Push enter to use the default length',
            type: 'number',
            when: (answers) => {
                // avoid length for decimal values
                if (answers.type === types_1.SqlType.DECIMAL || answers.type === types_1.SqlType.FLOAT)
                    return false;
                // set pivotAggregateName value
                if (answers.hasPivotTable) {
                    answers.pivotAggregateName = `${generateCommandState.schema.boundedContextName.toPascalCase()}${generateCommandState.schema.moduleNames.toPascalCase()}${name.toPascalCase()}`;
                    answers.pivotPath = `${generateCommandState.schema.boundedContextName}/${generateCommandState.schema.moduleName}`;
                    answers.pivotFileName = `${generateCommandState.schema.moduleNames.toKebabCase()}-${name.toKebabCase()}`;
                }
                if (!answers.hasPivotTable && answers.relationship === types_1.SqlRelationship.MANY_TO_MANY) {
                    const relationshipModulePath = (0, common_1.getBoundedContextModuleFromFlag)(generateCommandState.command, answers.relationshipModulePath);
                    answers.pivotAggregateName = `${relationshipModulePath.boundedContextName.toPascalCase()}${name.toPascalCase()}${generateCommandState.schema.moduleNames.toPascalCase()}`;
                    answers.pivotPath = answers.relationshipModulePath;
                    answers.pivotFileName = `${name.toKebabCase()}-${generateCommandState.schema.moduleNames.toKebabCase()}`;
                }
                if (answers.relationship)
                    return false;
                // eslint-disable-next-line unicorn/explicit-length-check
                return Object.keys(cliter_config_1.cliterConfig.defaultTypeLength).includes(answers.type) && !answers.length;
            },
        });
        questions.push({
            name: 'nullable',
            message: 'This property will be nullable?',
            type: 'confirm',
            when: (answers) => {
                if (answers.relationship === types_1.SqlRelationship.ONE_TO_MANY) {
                    // a field with relation one-to-many always will be nullable
                    answers.nullable = true;
                    return false;
                }
                if (answers.relationship === types_1.SqlRelationship.MANY_TO_MANY) {
                    // answers.nullable = true;
                    return false;
                }
                return true;
            },
        });
        const response = await inquirer.prompt(questions);
        // add default length
        // eslint-disable-next-line unicorn/explicit-length-check
        if (Object.keys(cliter_config_1.cliterConfig.defaultTypeLength).includes(response.type) && !response.length)
            response.length = cliter_config_1.cliterConfig.defaultTypeLength[response.type];
        // delete relationship none value
        if (response.relationship === types_1.SqlRelationship.NONE)
            delete response.relationship;
        return new property_1.Property({
            name: response.name,
            type: response.type,
            primaryKey: response.name === 'id' ? true : undefined,
            autoIncrement: response.autoIncrement,
            enumOptions: response.enumOptions,
            decimals: response.decimals,
            length: response.length,
            minLength: response.minLength,
            maxLength: response.maxLength,
            nullable: response.nullable,
            defaultValue: response.defaultValue,
            relationship: response.relationship,
            relationshipSingularName: response.relationshipSingularName,
            relationshipAggregate: response.relationshipAggregate,
            relationshipModulePath: response.relationshipModulePath,
            relationshipKey: response.relationship === types_1.SqlRelationship.MANY_TO_ONE ? 'id' : undefined,
            relationshipField: response.relationship === types_1.SqlRelationship.MANY_TO_ONE || (response.relationship === types_1.SqlRelationship.ONE_TO_ONE && response.name.endsWith('Id')) ? response.name.replace(new RegExp('Id$'), '').toCamelCase() : undefined,
            pivotAggregateName: response.pivotAggregateName,
            pivotPath: response.pivotPath,
            pivotFileName: response.pivotFileName,
            index: response.index,
        });
    },
    async promptAddPipeline(scope) {
        const questions = [];
        let platform = '';
        questions.push({
            name: 'from',
            message: 'From which platform will you deploy?',
            type: 'list',
            choices: cliter_config_1.cliterConfig.platformFromDeploy,
        });
        questions.push({
            name: 'to',
            message: 'to which platform will it be deployed?',
            type: 'list',
            choices: cliter_config_1.cliterConfig.platformToDeploy,
            validate: (input) => {
                platform = input;
                return true;
            },
        });
        questions.push({
            name: 'service',
            message: 'on what service will you deploy?',
            type: 'list',
            choices: (answers) => scope === 'front' ?
                cliter_config_1.cliterConfig.serviceToDeploy.front[answers.to.toCamelCase()] :
                cliter_config_1.cliterConfig.serviceToDeploy.back[answers.to.toCamelCase()],
        });
        return inquirer.prompt(questions);
    },
    async promptAddPackage(scope) {
        const questions = [];
        questions.push({
            name: 'packageName',
            message: 'Select the package to install',
            type: 'list',
            choices: types_1.Scope.FRONT === scope ?
                cliter_config_1.cliterConfig.frontPackages :
                cliter_config_1.cliterConfig.backPackages,
            // eslint-disable-next-line @typescript-eslint/no-unused-vars
            validate: (packageName) => true,
        });
        return inquirer.prompt(questions);
    },
    printValueObjectsTable(command, items) {
        const headers = [];
        const excludeHeaders = ['config', 'id', 'pivotAggregateName', 'pivotPath', 'pivotFileName'];
        const aliases = [
            { origin: '_name', alias: 'Name' },
            { origin: 'type', alias: 'Type' },
            { origin: 'primaryKey', alias: 'PK' },
            { origin: 'enumOptions', alias: 'Enums' },
            { origin: 'decimals', alias: 'Decimals' },
            { origin: 'length', alias: 'Length' },
            { origin: 'minLength', alias: 'MinL.' },
            { origin: 'maxLength', alias: 'MaxL.' },
            { origin: 'nullable', alias: 'Nullable' },
            { origin: 'relationship', alias: 'SqlRelationship' },
            { origin: 'relationshipSingularName', alias: 'Singular' },
            { origin: 'relationshipAggregate', alias: 'R. Aggregate' },
            { origin: 'relationshipModulePath', alias: 'R. Module Path' },
            { origin: 'relationshipKey', alias: 'R. Key' },
            { origin: 'relationshipField', alias: 'R. Field' },
            { origin: 'pivotAggregateName', alias: 'Pivot' },
            { origin: 'index', alias: 'Index' },
        ];
        const rows = [];
        // set headers
        for (const item of items) {
            for (const key in item) {
                if (item[key]) {
                    const alias = aliases.find(alias => alias.origin === key);
                    if (!headers.includes(alias ? alias.alias : key) && !excludeHeaders.includes(key))
                        headers.push(alias ? alias.alias : key);
                }
            }
        }
        // set rows in headers order
        for (const item of items) {
            const row = [];
            for (const header of headers) {
                const alias = aliases.find(alias => alias.alias === header);
                // get value for each header
                const value = header === 'Decimals' && Array.isArray(item.decimals) ?
                    item.decimals.join(',') :
                    (item[alias ?
                        alias.origin :
                        header] ?
                        item[alias ?
                            alias.origin :
                            header] : '');
                row.push(value);
            }
            rows.push(row);
        }
        const table = new Table({
            head: headers,
            chars: { top: '═', 'top-mid': '╤', 'top-left': '╔', 'top-right': '╗', bottom: '═', 'bottom-mid': '╧', 'bottom-left': '╚', 'bottom-right': '╝', left: '║', 'left-mid': '╟', mid: '─', 'mid-mid': '┼', right: '║', 'right-mid': '╢', middle: '│' },
        });
        table.push(...rows);
        command.log(table.toString());
    },
};
