/* jscpd:ignore-start */
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages, SfError } from '@salesforce/core';
import c from 'chalk';
import fs from 'fs-extra';
import pascalcase from 'pascalcase';
import * as path from 'path';
import { uxLog } from '../../../../common/utils/index.js';
import { DATA_FOLDERS_ROOT } from '../../../../common/utils/dataUtils.js';
import { prompts } from '../../../../common/utils/prompts.js';
import { WebSocketClient } from '../../../../common/websocketClient.js';
import { getConfig, setConfig } from '../../../../config/index.js';
import { PACKAGE_ROOT_DIR } from '../../../../settings.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('sfdx-hardis', 'org');
export default class ConfigureData extends SfCommand {
    static title = 'Configure Data project';
    static description = `
## Command Behavior

**Configures a Salesforce Data Migration Utility (SFDMU) project for data export and import operations.**

This command assists in setting up SFDMU workspaces, which are essential for managing data within your Salesforce environments. It streamlines the creation of \`export.json\` files and related configurations, enabling efficient data seeding, migration, and synchronization.

Key functionalities:

- **Template-Based Configuration:** Allows you to choose from predefined SFDMU templates or start with a blank configuration. Templates can pre-populate \`export.json\` with common data migration scenarios.
- **Interactive Setup:** Guides you through the process of defining the SFDMU project folder name, label, and description.
- **\`export.json\` Generation:** Creates the \`export.json\` file, which is the core configuration file for SFDMU, defining objects to export/import, queries, and operations.
- **Additional File Generation:** Can generate additional configuration files, such as a \`badwords.json\` file for data filtering scenarios.
- **Scratch Org Integration:** Offers to automatically configure the SFDMU project to be used for data import when initializing a new scratch org, ensuring consistent test data across development environments.

See this article for a practical example:

[![How to detect bad words in Salesforce records using SFDX Data Loader and sfdx-hardis](https://github.com/hardisgroupcom/sfdx-hardis/raw/main/docs/assets/images/article-badwords.jpg)](https://nicolas.vuillamy.fr/how-to-detect-bad-words-in-salesforce-records-using-sfdx-data-loader-and-sfdx-hardis-171db40a9bac)

<details markdown="1">
<summary>Technical explanations</summary>

The command's technical implementation involves:

- **SFDMU Integration:** It acts as a setup wizard for SFDMU, generating the necessary configuration files that the \`sfdmu\` plugin consumes.
- **Interactive Prompts:** Uses the \`prompts\` library to gather user input for various configuration parameters, such as the data path, label, and description.
- **File System Operations:** Employs \`fs-extra\` to create directories (e.g., \`data/your-project-name/\`) and write the \`export.json\` and any additional configuration files.
- **JSON Manipulation:** Constructs the \`export.json\` content dynamically based on user input and selected templates, including defining objects, queries, and operations.
- **PascalCase Conversion:** Uses \`pascalcase\` to format the SFDMU folder name consistently.
- **Configuration Persistence:** Updates the project's \`sfdx-hardis.yml\` file (via \`setConfig\`) to include the newly configured data package if it's intended for scratch org initialization.
- **WebSocket Communication:** Uses \`WebSocketClient.requestOpenFile\` to open the generated \`export.json\` file in VS Code, facilitating immediate configuration.
- **Required Plugin Check:** Explicitly lists \`sfdmu\` as a required plugin, ensuring the necessary dependency is present.
</details>
`;
    static examples = ['$ sf hardis:org:configure:data'];
    static flags = {
        debug: Flags.boolean({
            char: 'd',
            default: false,
            description: messages.getMessage('debugMode'),
        }),
        websocket: Flags.string({
            description: messages.getMessage('websocket'),
        }),
        skipauth: Flags.boolean({
            description: 'Skip authentication check when a default username is required',
        }),
    };
    // Set this to true if your command requires a project workspace; 'requiresProject' is false by default
    static requiresProject = false;
    // List required plugins, their presence will be tested before running the command
    static requiresSfdxPlugins = ['sfdmu'];
    additionalFiles = [];
    dataPath;
    sfdmuConfig;
    importInScratchOrgs;
    /* jscpd:ignore-end */
    async run() {
        const template = await this.selectTemplate();
        if (template === 'blank') {
            // Request info to build sfdmu workspace
            await this.buildExportJsonInfo();
        }
        else {
            await this.buildExportJsonInfoFromTemplate(template);
        }
        // Check if not already existing
        const { exportJsonFile, sfdmuProjectFolder } = await this.generateConfigurationFiles();
        await this.promptImportInScratchOrgs(sfdmuProjectFolder);
        // Set bac initial cwd
        const sfdmuBaseDoc = "https://help.sfdmu.com/configuration";
        const sfdmuExternalIdsDoc = "https://help.sfdmu.com/full-documentation/advanced-features/composite-external-id-keys";
        const message = c.cyan(`Successfully initialized sfdmu project ${c.green(sfdmuProjectFolder)}, with ${c.green('export.json')} file.`);
        uxLog("other", this, message);
        uxLog("log", this, c.grey(`You can now configure it using SFDMU documentation: ${c.yellow(sfdmuBaseDoc)}`));
        uxLog("log", this, c.grey(`If you don't have unique field to identify an object, use composite external ids: ${c.yellow(sfdmuExternalIdsDoc)}`));
        // Trigger command to open SFDMU config file in VsCode extension
        if (WebSocketClient.isAliveWithLwcUI()) {
            WebSocketClient.sendReportFileMessage(exportJsonFile, 'Edit your SFDMU export.json file', 'report');
            WebSocketClient.sendReportFileMessage(sfdmuBaseDoc, 'SFDMU documentation (Basic)', 'docUrl');
            WebSocketClient.sendReportFileMessage(sfdmuExternalIdsDoc, 'SFDMU documentation (External Ids)', 'docUrl');
        }
        else {
            WebSocketClient.requestOpenFile(exportJsonFile);
        }
        return { outputString: message };
    }
    async generateConfigurationFiles() {
        const sfdmuProjectFolder = path.join(DATA_FOLDERS_ROOT, this.dataPath);
        if (fs.existsSync(sfdmuProjectFolder)) {
            throw new SfError(`[sfdx-hardis]${c.red(`Folder ${c.bold(sfdmuProjectFolder)} already exists`)}`);
        }
        // Create folder & export.json
        await fs.ensureDir(sfdmuProjectFolder);
        const exportJsonFile = path.join(sfdmuProjectFolder, 'export.json');
        await fs.writeFile(exportJsonFile, JSON.stringify(this.sfdmuConfig, null, 2));
        uxLog("action", this, c.cyan('Generated SFDMU config file ' + exportJsonFile));
        for (const additionalFile of this.additionalFiles) {
            const additionalFileFull = path.join(sfdmuProjectFolder, additionalFile.path);
            await fs.writeFile(additionalFileFull, additionalFile.text);
            uxLog("action", this, c.cyan(additionalFile.message + ': ') + c.yellow(additionalFileFull));
            if (WebSocketClient.isAliveWithLwcUI()) {
                WebSocketClient.sendReportFileMessage(additionalFileFull, additionalFile.message, 'report');
            }
            else {
                WebSocketClient.requestOpenFile(additionalFileFull);
            }
        }
        return { exportJsonFile, sfdmuProjectFolder };
    }
    async buildExportJsonInfo() {
        const resp = await this.promptExportInfo();
        // Collect / reformat data
        this.dataPath = pascalcase(resp.dataPath);
        const sfdxHardisLabel = resp.sfdxHardisLabel;
        const sfdxHardisDescription = resp.sfdxHardisDescription;
        const additionalConfig = resp.additional || [];
        this.sfdmuConfig = {
            sfdxHardisLabel: sfdxHardisLabel,
            sfdxHardisDescription: sfdxHardisDescription,
            objects: [
                {
                    query: "SELECT all FROM Account WHERE Name='sfdx-hardis'",
                    operation: 'Upsert',
                    externalId: 'Name',
                },
            ],
        };
        // Manage badwords filter option
        if (additionalConfig.includes('badwordsFilter')) {
            const badwordsFileName = 'badwords.json';
            this.sfdmuConfig.objects[0] = [
                {
                    query: 'SELECT all FROM Lead',
                    operation: 'Readonly',
                    targetRecordsFilter: 'core:DetectBadwords',
                    filterRecordsAddons: [
                        {
                            module: 'core:RecordsFilter',
                            args: {
                                filterType: 'BadWords',
                                settings: {
                                    badwordsFile: badwordsFileName,
                                    detectFields: ['Description'],
                                    highlightWords: true,
                                    outputMatches: false,
                                },
                            },
                        },
                    ],
                },
            ];
            if (!fs.existsSync('badwords.json')) {
                const badwordsSample = {
                    badwords: ['write', 'your', 'bad', 'words', 'and expressions', 'here'],
                };
                this.additionalFiles.push({
                    path: badwordsFileName,
                    text: JSON.stringify(badwordsSample, null, 2),
                    message: 'Sample badwords file has been generated and needs to be updated',
                });
            }
        }
    }
    async promptExportInfo() {
        return await prompts([
            {
                type: 'text',
                name: 'dataPath',
                message: c.cyanBright('Please input the SFDMU folder name (PascalCase format)'),
                description: 'The folder name that will contain the SFDMU data configuration files',
                placeholder: 'Ex: ProductsActive',
            },
            {
                type: 'text',
                name: 'sfdxHardisLabel',
                message: c.cyanBright('Please input the SFDMU config label'),
                description: 'A human-readable label for this data configuration',
                placeholder: 'Ex: Active Products',
            },
            {
                type: 'text',
                name: 'sfdxHardisDescription',
                message: c.cyanBright('Please input the SFDMU config description'),
                description: 'A detailed description explaining what this data configuration does',
                placeholder: 'Ex: Active products are used for scratch org initialization and in deployments',
            },
            {
                type: 'multiselect',
                name: 'additional',
                message: c.cyanBright('Please select additional options if you need them'),
                description: 'Choose optional features to include in the data configuration (select nothing to skip)',
                choices: [
                    {
                        title: 'Bad words detector',
                        description: 'Can detect a list of bad words in records',
                        value: 'badwordsFilter',
                    },
                ],
            },
        ]);
    }
    async selectTemplate() {
        const templateChoices = [];
        const templatesFolder = path.join(PACKAGE_ROOT_DIR, 'defaults/templates/sfdmu');
        const templateFiles = fs.readdirSync(templatesFolder);
        for (const templateFile of templateFiles) {
            const templateName = path.basename(templateFile).replace('.json', '');
            templateChoices.push({
                title: `📝 ${templateName}`,
                value: path.join(templatesFolder, templateFile),
                description: `sfdx-hardis template for ${templateName}`,
            });
        }
        const defaultTemplateChoice = {
            title: '📄 Blank template',
            value: 'blank',
            description: 'Configure your data import/export from scratch :)',
        };
        const templateResp = await prompts({
            type: 'select',
            name: 'template',
            message: c.cyanBright('Please select a SFDMU template, or the blank one'),
            description: 'Choose a pre-configured SFDMU template for data operations or start with a blank configuration',
            placeholder: 'Select a template',
            choices: [...[defaultTemplateChoice], ...templateChoices],
        });
        return templateResp.template;
    }
    async buildExportJsonInfoFromTemplate(templateFile) {
        const templateName = path.basename(templateFile).replace('.json', '');
        this.dataPath = pascalcase(templateName);
        this.sfdmuConfig = JSON.parse(fs.readFileSync(templateFile, 'utf-8'));
    }
    async promptImportInScratchOrgs(sfdmuProjectFolder) {
        const importResp = await prompts({
            type: 'confirm',
            name: 'importInScratchOrgs',
            message: c.cyanBright('Do you want this SFDMU config to be used to import data when initializing a new scratch org ?'),
            description: 'Automatically import this data set when creating new scratch orgs for development and testing',
            default: false,
        });
        this.importInScratchOrgs = importResp.importInScratchOrgs === true;
        // Manage dataPackages if importInScratchOrgs is true
        if (this.importInScratchOrgs === true) {
            const config = await getConfig('project');
            const dataPackages = config.dataPackages || [];
            dataPackages.push({ dataPath: sfdmuProjectFolder.replace(/\\/g, '/'), importInScratchOrgs: true });
            await setConfig('project', { dataPackages: dataPackages });
        }
    }
}
//# sourceMappingURL=data.js.map