"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const contracts_1 = require("../../apis/codiac-api/contracts");
const command_base_exec_1 = require("../../command-base-exec");
const prettify_1 = require("../../prettify");
/** Filestore types that this command will provision as a Kubernetes PersistentVolumeClaim. */
const PVC_TYPES = [
    contracts_1.FileStoreTypeEnum.azureFileStorage,
    contracts_1.FileStoreTypeEnum.azureDisk,
    contracts_1.FileStoreTypeEnum.azureBlobStorage,
    contracts_1.FileStoreTypeEnum.azureNetAppFiles,
];
class PvcCreate extends command_base_exec_1.CommandBaseExec {
    captureArgs() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(PvcCreate);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if (flags.name)
                partial.name = flags.name;
            if (flags.provider)
                partial.provider = flags.provider;
            if (flags.type)
                partial.type = flags.type;
            if (flags["share-name"])
                partial.shareName = flags["share-name"];
            if (flags["storage-class"])
                partial.storageClass = flags["storage-class"];
            if (flags["access-modes"])
                partial.accessModes = PvcCreate.parseAccessModes(flags["access-modes"]);
            if (flags.size)
                partial.storageRequest = flags.size;
            if (flags["volume-name"])
                partial.volumeName = flags["volume-name"];
            const takeDefaults = (_a = flags['take-defaults']) !== null && _a !== void 0 ? _a : false;
            return [partial, takeDefaults];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.name || partial.name.trim() == "")
                throw new Error("--name is required.");
            const provider = (_a = partial.provider) !== null && _a !== void 0 ? _a : contracts_1.CloudProviderEnum.azure;
            if (provider !== contracts_1.CloudProviderEnum.azure) {
                throw new Error("Only --provider azure is supported at this time.");
            }
            const type = (_b = partial.type) !== null && _b !== void 0 ? _b : contracts_1.FileStoreTypeEnum.azureFileStorage;
            if (!PVC_TYPES.includes(type)) {
                throw new Error(`--type must be one of: ${PVC_TYPES.join(", ")}.`);
            }
            return this.assemble(partial, provider, type);
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.name || partial.name.trim() == "") {
                partial.name = (yield this._ui.prompt("pvcName", "Name for this PVC filestore", true));
            }
            if (!partial.name || partial.name.trim() == "") {
                this._ui.userMessage("Name is required.");
                return undefined;
            }
            if (!partial.provider) {
                partial.provider = contracts_1.CloudProviderEnum.azure;
            }
            if (partial.provider !== contracts_1.CloudProviderEnum.azure) {
                this._ui.userMessage("Only Azure is supported for PVC creation at this time.");
                this.exit(1);
                return undefined;
            }
            if (!partial.type) {
                const choices = PVC_TYPES.map(v => ({ name: v, value: v }));
                partial.type = (yield this._ui.promptSelect("pvcType", "Select the file storage type", choices));
            }
            const candidate = this.assemble(partial, partial.provider, partial.type);
            if (!candidate)
                return undefined;
            this._ui.userMessage((0, prettify_1.prettify)(candidate));
            const confirmed = yield this._ui.promptConfirm("pvcConfirm", `Create PVC filestore [${candidate.name}] (type: ${candidate.type})?`, true);
            return confirmed ? candidate : undefined;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("--silent");
        cmd.push("--enterprise", candidate.enterprise);
        cmd.push("--name", candidate.name);
        cmd.push("--provider", candidate.provider);
        cmd.push("--type", candidate.type);
        if (candidate.shareName && candidate.shareName !== candidate.name)
            cmd.push("--share-name", candidate.shareName);
        if (candidate.storageClass)
            cmd.push("--storage-class", candidate.storageClass);
        if (candidate.accessModes && candidate.accessModes.length > 0)
            cmd.push("--access-modes", candidate.accessModes.join(","));
        if (candidate.storageRequest)
            cmd.push("--size", candidate.storageRequest);
        if (candidate.volumeName)
            cmd.push("--volume-name", candidate.volumeName);
        return cmd;
    }
    executeTask(candidate) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const result = yield this._codiacApi.FileStoreDef.tryCreate(candidate);
                if (result.error)
                    throw result.error;
                if (!result.success || !result.output)
                    throw new Error(`Failed without error writing FileStoreDef record [${candidate.name}]: ${result.message}.`);
                const msg = `${this._styler.colorGood("SUCCESS!")} Created PVC filestore ${this._styler.bold(this._styler.hilite(candidate.name))} (type: ${candidate.type}).`;
                this.logger.notice(msg, result.output);
                this._ui.userMessage(msg);
            }
            catch (err) {
                this.logger.error((_b = (_a = err.message) !== null && _a !== void 0 ? _a : err.stack) !== null && _b !== void 0 ? _b : err, candidate);
                throw err;
            }
        });
    }
    /** Builds the FileStoreDef-shaped candidate from the resolved partial. */
    assemble(partial, provider, type) {
        var _a;
        const name = partial.name;
        const shareName = (_a = partial.shareName) !== null && _a !== void 0 ? _a : name;
        const audit = this.createAuditable();
        const candidate = Object.assign({ name,
            shareName,
            provider,
            type, 
            // Sentinel value to signify "this filestore is not bound to a CSP subscription".
            // The PVC path doesn't use the CSP subscription, but the field is required by FileStoreDef.
            providerSubscriptionId: "pvc", instance: undefined, enterprise: partial.enterprise }, audit);
        if (partial.storageClass)
            candidate.storageClass = partial.storageClass;
        if (partial.accessModes && partial.accessModes.length > 0)
            candidate.accessModes = partial.accessModes;
        if (partial.storageRequest)
            candidate.storageRequest = partial.storageRequest;
        if (partial.volumeName)
            candidate.volumeName = partial.volumeName;
        return candidate;
    }
    /** Parses a comma-separated string of access modes into the typed enum array.
     *  Throws on any unrecognized value to fail loudly rather than silently dropping. */
    static parseAccessModes(raw) {
        const allowed = new Set(Object.values(contracts_1.K8sAccessModeEnum));
        const tokens = raw.split(",").map(s => s.trim()).filter(s => s.length > 0);
        const out = [];
        for (const t of tokens) {
            if (!allowed.has(t)) {
                throw new Error(`Invalid access mode '${t}'. Allowed values: ${Object.values(contracts_1.K8sAccessModeEnum).join(", ")}.`);
            }
            out.push(t);
        }
        return out;
    }
}
exports.default = PvcCreate;
PvcCreate.description = 'Defines a new PersistentVolumeClaim-backed filestore for the given enterprise. The filestore is realized as a PVC in the target cabinet at deploy time, using either a Kubernetes StorageClass for dynamic provisioning or a pre-existing PersistentVolume for static binding.';
PvcCreate.aliases = ['pvc:create'];
PvcCreate.dependsOn = ["enterprise", "name"];
PvcCreate.examples = [
    {
        description: 'Azure File share, dynamic provisioning, default size.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name shared-files --type AzureFileStorage',
    },
    {
        description: 'Azure Disk per-asset (block storage), 50Gi.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name app-disk --type AzureDisk --size 50Gi',
    },
    {
        description: 'Azure Blob (fuse), 100Gi, statically bound to a pre-existing PV.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name pvc-blob --type AzureBlobStorage --size 100Gi --volume-name pv-blob-ingestion',
    },
    {
        description: 'Azure NetApp Files, statically bound, 700Gi.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name pvc-nfs41-document-vault --type AzureNetAppFiles --size 700Gi --volume-name pv-nfs41-document-vault',
    },
    {
        description: 'Override the default storage class (e.g., the in-tree azurefile class) on a non-prefixed PVC name.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name app-documents-share --type AzureFileStorage --size 700Gi --storage-class azurefile --access-modes ReadWriteMany',
    },
    {
        description: 'Non-interactive (scripted) invocation.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name shared-files --type AzureFileStorage --silent',
    },
    {
        description: 'Renders the equivalent silent command and then executes.',
        command: '<%= config.bin %> <%= command.id %> -e myEnt --name shared-files --type AzureFileStorage --echo',
    },
];
PvcCreate.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    enterprise: core_1.Flags.string({ char: 'e', required: false, description: 'Code name identifying the enterprise that will own this filestore reference.' }),
    name: core_1.Flags.string({ char: 'n', required: false, description: 'Name by which this filestore is identified within the enterprise. Used to derive the PVC name.' }),
    provider: core_1.Flags.string({ required: false, options: Object.values(contracts_1.CloudProviderEnum), description: `Cloud provider hosting the underlying storage (defaults to ${contracts_1.CloudProviderEnum.azure}; only Azure is supported at this time).` }),
    type: core_1.Flags.string({ char: 't', required: false, options: PVC_TYPES, description: `Storage technology backing the PVC (defaults to ${contracts_1.FileStoreTypeEnum.azureFileStorage}).` }),
    "share-name": core_1.Flags.string({ required: false, description: "Underlying physical share name (used by the legacy AzureFileStorage path; ignored for native PVC types). Defaults to the value of --name." }),
    "storage-class": core_1.Flags.string({ required: false, description: "Kubernetes StorageClass to bind to (e.g. 'azurefile', 'azureblob-fuse-premium', 'azure-netapp-files', 'managed-csi'). Defaults to a sensible per-type class when omitted." }),
    "access-modes": core_1.Flags.string({ required: false, description: `Comma-separated PVC access modes (e.g. 'ReadWriteMany' or 'ReadWriteOnce,ReadOnlyMany'). Defaults to RWO for block storage, RWM for file/object/NAS storage. Allowed values: ${Object.values(contracts_1.K8sAccessModeEnum).join(", ")}.` }),
    size: core_1.Flags.string({ required: false, description: "Storage capacity request as a Kubernetes quantity (e.g. '5Gi', '100Gi', '700Gi'). Defaults to 500Mi." }),
    "volume-name": core_1.Flags.string({ required: false, description: "Name of a pre-existing PersistentVolume to bind to. When set, the PVC binds statically to that PV instead of triggering dynamic provisioning." }),
    silent: core_1.Flags.boolean({ dependsOn: PvcCreate.dependsOn, required: false, exclusive: ["echo", "to-script"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
    "take-defaults": core_1.Flags.boolean({ exclusive: ["silent"], description: "Setting this to true prevents prompting for confirmation on parameters that were passed in or were automatically set to default values (Irrelevant in --silent mode)." }),
};
//# sourceMappingURL=create.js.map