"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs = require("fs");
const core_1 = require("@oclif/core");
const contracts_1 = require("../../../apis/codiac-relay/contracts");
const command_base_exec_tenant_1 = require("../../../command-base-exec-tenant");
class NocClusterCredentialsSet extends command_base_exec_tenant_1.CommandBaseExecTenant {
    // ---------------------------------------------------------------------------
    // Lifecycle methods
    // ---------------------------------------------------------------------------
    captureArgs() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(NocClusterCredentialsSet);
            const takeDefaults = (_a = flags['take-defaults']) !== null && _a !== void 0 ? _a : false;
            const kubeconfigYaml = this.resolveKubeconfigYaml(flags.file);
            const partial = {
                clusterName: args.name,
                kubeconfigYaml,
                contextName: flags.context,
            };
            return [partial, takeDefaults];
        });
    }
    buildCandidate_silently(partial, _rootMap) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.clusterName)
                throw new Error('Cluster name is required (pass it as the first argument).');
            if (!partial.kubeconfigYaml)
                throw new Error('Kubeconfig content is required. Use --file <path> or pipe via stdin.');
            return partial;
        });
    }
    buildCandidate_interactively(partial, _takeDefaults, _rootMap) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.clusterName) {
                partial.clusterName = yield this.promptForOtherCluster();
            }
            if (!partial.kubeconfigYaml) {
                const filePath = yield this._ui.promptSelectFile('file', 'Select kubeconfig file:', { extensions: ['yaml', 'yml', ''] });
                partial.kubeconfigYaml = this.resolveKubeconfigYaml(filePath);
            }
            return partial;
        });
    }
    /** Fetches ClusterDefs with provider "other" and prompts the user to pick one. */
    promptForOtherCluster() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const result = yield this._codiacApi.ClusterDef.tryReadMany({});
            const clusters = ((_a = result.output) !== null && _a !== void 0 ? _a : []).filter(c => c.provider === contracts_1.CloudProviderEnum.other);
            if (clusters.length === 0) {
                throw new Error('No self-managed clusters found. ' +
                    'Define one first with `cod cluster define --provider other` and then run this command again.');
            }
            const choices = clusters.map(c => ({ name: c.name, value: c.name }));
            return (yield this._ui.promptSelect('clusterName', 'Cluster:', choices, false, false));
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push(candidate.clusterName);
        // We can't embed the full YAML inline in the command string, so emit the stdin form.
        cmd.push('--silent');
        if (candidate.contextName)
            cmd.push('--context', candidate.contextName);
        return cmd;
    }
    executeTask(candidate) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const result = yield this.genRelayClient.Call.otherClusterCredentialsSet({
                clusterName: candidate.clusterName,
                kubeconfigYaml: candidate.kubeconfigYaml,
                contextName: candidate.contextName,
            });
            if (result.error) {
                const msg = `Error setting credentials for cluster [${candidate.clusterName}]: ${(_a = result.message) !== null && _a !== void 0 ? _a : ''} ${(_b = result.error.message) !== null && _b !== void 0 ? _b : ''}`.trimEnd();
                this.logger.error(msg, result.error);
                this._ui.userMessage(`${this._styler.colorCritical('ERROR!')} ${msg}`);
            }
            else if (!result.success) {
                const msg = `Credentials set failed for [${candidate.clusterName}]: ${(_c = result.message) !== null && _c !== void 0 ? _c : ''}`.trimEnd();
                this.logger.notice(msg, result);
                this._ui.userMessage(`${this._styler.colorCritical('FAILED!')} ${msg}`);
            }
            else {
                this._ui.userMessage(`${this._styler.colorGood('SUCCESS!')} Credentials registered for cluster [${this._styler.hilite(candidate.clusterName)}]. ` +
                    `Run \`cod noc cluster restore ${candidate.clusterName} --no-provision\` to bootstrap it.`);
            }
        });
    }
    // ---------------------------------------------------------------------------
    // Helpers
    // ---------------------------------------------------------------------------
    /**
     * Returns kubeconfig YAML from the given file path, or from stdin if
     * content was piped in and no file path was supplied.
     */
    resolveKubeconfigYaml(filePath) {
        var _a;
        if (filePath) {
            if (!fs.existsSync(filePath))
                throw new Error(`File not found: ${filePath}`);
            return fs.readFileSync(filePath, 'utf-8');
        }
        return (_a = this.pipedInput) !== null && _a !== void 0 ? _a : undefined;
    }
}
exports.default = NocClusterCredentialsSet;
NocClusterCredentialsSet.description = 'Registers connection credentials for a self-managed cluster (provider: other). ' +
    'Supply a kubeconfig file via --file or pipe it via stdin. ' +
    'When the file contains multiple contexts, specify which one to use with --context. ' +
    'If there is only one context, it is ingested automatically.';
NocClusterCredentialsSet.aliases = ['cluster:credentials-set'];
NocClusterCredentialsSet.examples = [
    {
        description: 'Register credentials from a file (single-context kubeconfig).',
        command: '<%= config.bin %> <%= command.id %> my-cluster --file ~/.kube/my-cluster.yaml',
    },
    {
        description: 'Multi-context kubeconfig — auto-selected because one context references a cluster named my-cluster.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --file ~/.kube/config',
    },
    {
        description: 'Multi-context kubeconfig — explicit context when auto-selection is ambiguous.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --file ~/.kube/config --context my-cluster-admin',
    },
    {
        description: 'Pipe a kubeconfig in via stdin.',
        command: 'cat ~/.kube/my-cluster.yaml | <%= config.bin %> <%= command.id %> my-cluster',
    },
    {
        description: 'Non-interactive (scripted) invocation.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --file ~/.kube/my-cluster.yaml --silent',
    },
];
NocClusterCredentialsSet.flags = {
    file: core_1.Flags.string({
        char: 'f',
        description: 'Path to a kubeconfig file. Mutually exclusive with stdin.',
    }),
    context: core_1.Flags.string({
        char: 'x',
        description: 'Name of the context to extract from a multi-context kubeconfig. ' +
            'If omitted and exactly one context references a cluster matching the cluster name argument, that context is selected automatically. ' +
            'Required only when the match is ambiguous.',
    }),
    silent: core_1.Flags.boolean({
        exclusive: ['echo', 'to-script'],
        description: 'Non-interactive mode; executes without user interaction and fails on missing or invalid arguments.',
        relationships: [
            { type: 'all', flags: ['file'] },
        ],
    }),
    echo: core_1.Flags.boolean({
        exclusive: ['to-script', 'silent'],
        description: 'Renders the equivalent non-interactive command before executing.',
    }),
    'to-script': core_1.Flags.boolean({
        exclusive: ['echo', 'silent'],
        description: 'Renders the equivalent non-interactive command without executing.',
    }),
    'take-defaults': core_1.Flags.boolean({
        exclusive: ['silent'],
        description: 'Prevents prompting for confirmation on parameters already provided.',
    }),
};
NocClusterCredentialsSet.args = {
    name: core_1.Args.string({ description: 'Name of the cluster to register credentials for.' }),
};
//# sourceMappingURL=credentials-set.js.map