/* jscpd:ignore-start */
import { SfCommand, Flags, requiredHubFlagWithDeprecations } from '@salesforce/sf-plugins-core';
import { Messages, SfError } from '@salesforce/core';
import c from 'chalk';
import { MetadataUtils } from '../../../../common/metadata-utils/index.js';
import { execSfdxJson, isCI, uxLog } from '../../../../common/utils/index.js';
import { prompts } from '../../../../common/utils/prompts.js';
import { getConfig, setConfig } from '../../../../config/index.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('sfdx-hardis', 'org');
export default class PackageVersionCreate extends SfCommand {
    static title = 'Create a new version of a package';
    static description = `
## Command Behavior

**Creates a new version of a Salesforce package (2GP or Unlocked) in your Dev Hub.**

This command is a crucial step in the package development lifecycle, allowing you to iterate on your Salesforce functionalities and prepare them for deployment or distribution. It automates the process of creating a new, immutable package version.

Key functionalities:

- **Package Selection:** Prompts you to select an existing package from your \`sfdx-project.json\` file if not specified via the \`--package\` flag.
- **Installation Key:** Allows you to set an installation key (password) for the package version, protecting it from unauthorized installations. This can be provided via the \`--installkey\` flag or interactively.
- **Code Coverage:** Automatically includes code coverage checks during package version creation.
- **Post-Creation Actions:**
  - **Delete After Creation (\`--deleteafter\`):** Deletes the newly created package version immediately after its creation. This is useful for testing the package creation process without accumulating unnecessary versions.
  - **Install After Creation (\`--install\`):** Installs the newly created package version on your default Salesforce org. This is convenient for immediate testing or validation.

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

The command's technical implementation involves:

- **Package Directory Identification:** It identifies the package directory from your \`sfdx-project.json\` based on the selected package name.
- **Interactive Prompts:** Uses the \`prompts\` library to guide the user through package selection and installation key input if not provided as command-line arguments.
- **Configuration Persistence:** Stores the \`defaultPackageInstallationKey\` in your project's configuration (\`.sfdx-hardis.yml\`) for future use.
- **Salesforce CLI Integration:** It constructs and executes the \`sf package version create\` command, passing the package ID, installation key, and other flags.
- **\`execSfdxJson\`:** This utility is used to execute the Salesforce CLI command and capture its JSON output, which includes the \`SubscriberPackageVersionId\` of the newly created version.
- **Post-Creation Command Execution:** If \`--deleteafter\` or \`--install\` flags are set, it executes \`sf package version delete\` or delegates to \`MetadataUtils.installPackagesOnOrg\` respectively.
- **Error Handling:** Includes checks for missing package arguments and handles errors during package version creation or post-creation actions.
</details>
`;
    static examples = ['$ sf hardis:package:version:create'];
    // public static args = [{name: 'file'}];
    static flags = {
        debug: Flags.boolean({
            char: 'd',
            default: false,
            description: messages.getMessage('debugMode'),
        }),
        package: Flags.string({
            char: 'p',
            default: '',
            description: 'Package identifier that you want to use to generate a new package version',
        }),
        installkey: Flags.string({
            char: 'k',
            default: '',
            description: 'Package installation key',
        }),
        deleteafter: Flags.boolean({
            default: false,
            description: 'Delete package version after creating it',
        }),
        install: Flags.boolean({
            char: 'i',
            default: false,
            description: 'Install package version on default org after generation',
        }),
        websocket: Flags.string({
            description: messages.getMessage('websocket'),
        }),
        skipauth: Flags.boolean({
            description: 'Skip authentication check when a default username is required',
        }),
        'target-dev-hub': requiredHubFlagWithDeprecations,
    };
    // Set this to true if your command requires a project workspace; 'requiresProject' is false by default
    static requiresProject = true;
    package;
    deleteAfter = false;
    install = false;
    installKey = null;
    promote = false;
    /* jscpd:ignore-end */
    async run() {
        const { flags } = await this.parse(PackageVersionCreate);
        this.package = flags.package || null;
        this.install = flags.install || false;
        this.installKey = flags.installkey || null;
        this.deleteAfter = flags.deleteafter || false;
        //this.promote = flags.promote || false;
        const debugMode = flags.debug || false;
        const config = await getConfig('project');
        // List project packages
        const packageDirectories = this.project?.getUniquePackageDirectories() || [];
        // Ask user to select package and input install key if not sent as command arguments
        if (this.package == null) {
            if (isCI) {
                throw new SfError("You need to send argument 'package'");
            }
            const packageResponse = await prompts([
                {
                    type: 'select',
                    name: 'packageSelected',
                    message: c.cyanBright(`Please select a package (this is not a drill, it will create an official new version !)`),
                    description: 'Choose which package to create a new version for - this action creates a permanent version',
                    placeholder: 'Select a package',
                    choices: packageDirectories.map((packageDirectory) => {
                        return {
                            title: packageDirectory?.package || packageDirectory?.path || packageDirectory?.fullPath || packageDirectory?.name,
                            value: packageDirectory.name,
                        };
                    }),
                },
                {
                    type: 'text',
                    name: 'packageInstallationKey',
                    message: c.cyanBright('Do you want to password protect your package ? (blank means no)'),
                    description: 'Optionally set a password to protect the package installation',
                    placeholder: 'Ex: mySecretPassword123',
                    initial: config.defaultPackageInstallationKey || '',
                },
            ]);
            this.package = packageResponse.packageSelected;
            this.installKey = packageResponse.packageInstallationKey;
        }
        // Identify package directory
        const pckgDirectory = packageDirectories.filter((pckgDirectory) => pckgDirectory.name === this.package || pckgDirectory.package === this.package)[0];
        if (config.defaultPackageInstallationKey !== this.installKey && this.installKey != null) {
            await setConfig('project', {
                defaultPackageInstallationKey: this.installKey,
            });
        }
        // Create package version
        uxLog("action", this, c.cyan(`Generating new package version for ${c.green(pckgDirectory.package)}...`));
        const createCommand = 'sf package version create' +
            ` --package "${pckgDirectory.package}"` +
            (this.installKey ? ` --installation-key "${this.installKey}"` : ' --installation-key-bypass') +
            ' --code-coverage' +
            ' --wait 60';
        const createResult = await execSfdxJson(createCommand, this, {
            fail: true,
            output: true,
            debug: debugMode,
        });
        const latestVersion = createResult.result.SubscriberPackageVersionId;
        // If delete after is true, delete package version we just created
        if (this.deleteAfter) {
            // Delete package version
            uxLog("action", this, c.cyan(`Delete new package version ${c.green(latestVersion)} of package ${c.green(pckgDirectory.package)}...`));
            const deleteVersionCommand = 'sf package version delete --no-prompt --package ' + latestVersion;
            const deleteVersionResult = await execSfdxJson(deleteVersionCommand, this, {
                fail: true,
                output: true,
                debug: debugMode,
            });
            if (!(deleteVersionResult.result.success === true)) {
                throw new SfError(`Unable to delete package version ${latestVersion}`);
            }
        }
        // Install package on org just after is has been generated
        else if (this.install) {
            const packagesToInstall = [];
            const pckg = {
                SubscriberPackageVersionId: latestVersion,
            };
            if (this.installKey) {
                pckg.installationkey = this.installKey;
            }
            packagesToInstall.push(pckg);
            await MetadataUtils.installPackagesOnOrg(packagesToInstall, null, this, 'install');
        }
        // Return an object to be displayed with --json
        return {
            outputString: 'Generated new package version',
            packageVersionId: latestVersion,
        };
    }
}
//# sourceMappingURL=create.js.map