/*
 * Copyright (c) 2025, Salesforce, Inc.
 * SPDX-License-Identifier: Apache-2
 * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
 */
import { Flags } from '@oclif/core';
import { BaseCommand } from './base-command.js';
import { loadConfig, ALL_AUTH_METHODS } from './config.js';
import { OAuthStrategy } from '../auth/oauth.js';
import { ImplicitOAuthStrategy } from '../auth/oauth-implicit.js';
import { t } from '../i18n/index.js';
import { DEFAULT_ACCOUNT_MANAGER_HOST } from '../defaults.js';
/**
 * Base command for operations requiring OAuth authentication.
 * Use this for platform-level operations like ODS, APIs.
 *
 * Environment variables:
 * - SFCC_CLIENT_ID: OAuth client ID
 * - SFCC_CLIENT_SECRET: OAuth client secret
 *
 * For B2C instance specific operations, use InstanceCommand instead.
 */
export class OAuthCommand extends BaseCommand {
    static baseFlags = {
        ...BaseCommand.baseFlags,
        'client-id': Flags.string({
            description: 'Client ID for OAuth',
            env: 'SFCC_CLIENT_ID',
            helpGroup: 'AUTH',
        }),
        'client-secret': Flags.string({
            description: 'Client Secret for OAuth',
            env: 'SFCC_CLIENT_SECRET',
            helpGroup: 'AUTH',
        }),
        scope: Flags.string({
            description: 'OAuth scopes to request (comma-separated)',
            env: 'SFCC_OAUTH_SCOPES',
            multiple: true,
            multipleNonGreedy: true,
            delimiter: ',',
            helpGroup: 'AUTH',
        }),
        'short-code': Flags.string({
            description: 'SCAPI short code',
            env: 'SFCC_SHORTCODE',
            helpGroup: 'AUTH',
        }),
        'tenant-id': Flags.string({
            description: 'Organization/tenant ID',
            env: 'SFCC_TENANT_ID',
            helpGroup: 'AUTH',
        }),
        'auth-methods': Flags.string({
            description: 'Allowed auth methods in priority order (comma-separated)',
            env: 'SFCC_AUTH_METHODS',
            multiple: true,
            multipleNonGreedy: true,
            delimiter: ',',
            options: ALL_AUTH_METHODS,
            helpGroup: 'AUTH',
        }),
        'account-manager-host': Flags.string({
            description: `Account Manager hostname for OAuth (default: ${DEFAULT_ACCOUNT_MANAGER_HOST})`,
            env: 'SFCC_ACCOUNT_MANAGER_HOST',
            helpGroup: 'AUTH',
        }),
    };
    /**
     * Parses auth methods from flags.
     * Returns methods in the order specified (priority order).
     */
    parseAuthMethods() {
        const flagValues = this.flags['auth-methods'];
        if (!flagValues || flagValues.length === 0) {
            return undefined;
        }
        // Filter to valid auth methods (oclif handles comma splitting via delimiter)
        const methods = flagValues
            .map((s) => s.trim())
            .filter((s) => ALL_AUTH_METHODS.includes(s));
        return methods.length > 0 ? methods : undefined;
    }
    loadConfiguration() {
        const options = {
            instance: this.flags.instance,
            configPath: this.flags.config,
        };
        const flagConfig = {
            clientId: this.flags['client-id'],
            clientSecret: this.flags['client-secret'],
            shortCode: this.flags['short-code'],
            tenantId: this.flags['tenant-id'],
            authMethods: this.parseAuthMethods(),
            accountManagerHost: this.flags['account-manager-host'],
            // Merge scopes from flags (if provided)
            scopes: this.flags.scope && this.flags.scope.length > 0 ? this.flags.scope : undefined,
        };
        const pluginSources = {
            before: this.pluginSourcesBefore,
            after: this.pluginSourcesAfter,
        };
        return loadConfig(flagConfig, options, pluginSources);
    }
    /**
     * Gets the configured Account Manager host.
     */
    get accountManagerHost() {
        return this.resolvedConfig.values.accountManagerHost ?? DEFAULT_ACCOUNT_MANAGER_HOST;
    }
    /**
     * Gets an OAuth auth strategy based on allowed auth methods and available credentials.
     *
     * Iterates through allowed methods (in priority order) and returns the first
     * strategy for which the required credentials are available.
     *
     * @throws Error if no allowed method has the required credentials configured
     */
    getOAuthStrategy() {
        const config = this.resolvedConfig.values;
        const accountManagerHost = this.accountManagerHost;
        // Default to client-credentials and implicit if no methods specified
        const allowedMethods = config.authMethods || ['client-credentials', 'implicit'];
        for (const method of allowedMethods) {
            switch (method) {
                case 'client-credentials':
                    if (config.clientId && config.clientSecret) {
                        return new OAuthStrategy({
                            clientId: config.clientId,
                            clientSecret: config.clientSecret,
                            scopes: config.scopes,
                            accountManagerHost,
                        });
                    }
                    break;
                case 'implicit':
                    if (config.clientId) {
                        return new ImplicitOAuthStrategy({
                            clientId: config.clientId,
                            scopes: config.scopes,
                            accountManagerHost,
                        });
                    }
                    break;
                // 'basic' and 'api-key' are not applicable for OAuth strategies
                // They would be handled by different command bases (e.g., InstanceCommand, MRTCommand)
            }
        }
        // Build helpful error message based on what methods were allowed
        const methodsStr = allowedMethods.join(', ');
        throw new Error(t('error.noValidAuthMethod', `No valid auth method available. Allowed methods: [${methodsStr}]. ` +
            `Ensure required credentials are configured for at least one method.`));
    }
    /**
     * Check if OAuth credentials are available.
     * Returns true if clientId is configured (with or without clientSecret).
     */
    hasOAuthCredentials() {
        return this.resolvedConfig.hasOAuthConfig();
    }
    /**
     * Check if full OAuth credentials (client credentials flow) are available.
     * Returns true only if both clientId and clientSecret are configured.
     */
    hasFullOAuthCredentials() {
        const config = this.resolvedConfig.values;
        return Boolean(config.clientId && config.clientSecret);
    }
    /**
     * Validates that OAuth credentials are configured, errors if not.
     * Only clientId is required (implicit flow can be used without clientSecret).
     */
    requireOAuthCredentials() {
        if (!this.hasOAuthCredentials()) {
            this.error(t('error.oauthClientIdRequired', 'OAuth client ID required. Provide --client-id or set SFCC_CLIENT_ID.'));
        }
    }
}
//# sourceMappingURL=oauth-command.js.map