const require_logger_index = require('../logger/index.js');

//#region src/params/types.ts
const EXPRESSION_TAG = Symbol.for("firebase-functions:Expression:Tag");
var Expression = class {
	/**
	* Handle the "Dual-Package Hazard" .
	*
	* We implement custom `Symbol.hasInstance` to so CJS/ESM Expression instances
	* are recognized as the same type.
	*/
	static [Symbol.hasInstance](instance) {
		return instance?.[EXPRESSION_TAG] === true;
	}
	get [EXPRESSION_TAG]() {
		return true;
	}
	/** Returns the expression's runtime value, based on the CLI's resolution of parameters. */
	value() {
		if (process.env.FUNCTIONS_CONTROL_API === "true") {
			require_logger_index.warn(`${this.toString()}.value() invoked during function deployment, instead of during runtime.`);
			require_logger_index.warn(`This is usually a mistake. In configs, use Params directly without calling .value().`);
			require_logger_index.warn(`example: { memory: memoryParam } not { memory: memoryParam.value() }`);
		}
		return this.runtimeValue();
	}
	/** @internal */
	runtimeValue() {
		throw new Error("Not implemented");
	}
	/** Returns the expression's representation as a braced CEL expression. */
	toCEL(_transform = (a) => a) {
		return `{{ ${this.toString()} }}`;
	}
	/** Returns the expression's representation as JSON. */
	toJSON() {
		return this.toString();
	}
};
/**
* An InterpolationExpression allows string fragments and Expressions to be
* joined natively into a new Expression block evaluating to a string string.
*/
var InterpolationExpression = class extends Expression {
	constructor(strings, values) {
		super();
		this.strings = strings;
		this.values = values;
	}
	/** @internal */
	runtimeValue() {
		return this.strings.reduce((result, str, i) => {
			const val = i < this.values.length ? String(valueOf(this.values[i])) : "";
			return result + str + val;
		}, "");
	}
	toCEL(transform$1 = (a) => a) {
		const exprPlaceholders = [];
		const PLACEHOLDER_PREFIX = "🤿🤿🤿🐙🐙🐙";
		const PLACEHOLDER_SUFFIX = "🐙🐙🐙🤿🤿🤿";
		const rawString = this.strings.reduce((result, str, i) => {
			if (i >= this.values.length) {
				return result + str;
			}
			const val = this.values[i];
			let valStr;
			if (val instanceof Expression) {
				valStr = `${PLACEHOLDER_PREFIX}${exprPlaceholders.length}${PLACEHOLDER_SUFFIX}`;
				exprPlaceholders.push(val.toCEL());
			} else {
				valStr = String(val);
			}
			return result + str + valStr;
		}, "");
		let transformed = transform$1(rawString);
		for (let i = 0; i < exprPlaceholders.length; i++) {
			const placeholder = `${PLACEHOLDER_PREFIX}${i}${PLACEHOLDER_SUFFIX}`;
			transformed = transformed.split(placeholder).join(exprPlaceholders[i]);
		}
		return transformed;
	}
};
/** @internal */
var TransformedStringExpression = class extends Expression {
	constructor(source, transformer) {
		super();
		this.source = source;
		this.transformer = transformer;
	}
	runtimeValue() {
		return this.transformer(valueOf(this.source));
	}
	toCEL() {
		return this.source instanceof Expression ? this.source.toCEL(this.transformer) : this.transformer(this.source);
	}
};
function valueOf(arg) {
	return arg instanceof Expression ? arg.runtimeValue() : arg;
}
function celOf(arg) {
	return arg instanceof Expression ? arg.toCEL() : arg;
}
/**
* Transforms a string or a string expression using a function.
*/
function transform(source, transformer) {
	return new TransformedStringExpression(source, transformer);
}
/**
* Returns how an entity (either an `Expression` or a literal value) should be represented in CEL.
* - Expressions delegate to the `.toString()` method, which is used by the WireManifest
* - Strings have to be quoted explicitly
* - Arrays are represented as []-delimited, parsable JSON
* - Numbers and booleans are not quoted explicitly
*/
function refOf(arg) {
	if (arg instanceof Expression) {
		return arg.toString();
	} else if (typeof arg === "string") {
		return `"${arg}"`;
	} else if (Array.isArray(arg)) {
		return JSON.stringify(arg);
	} else {
		return arg.toString();
	}
}
/**
* A CEL expression corresponding to a ternary operator, e.g {{ cond ? ifTrue : ifFalse }}
*/
var TernaryExpression = class extends Expression {
	constructor(test, ifTrue, ifFalse) {
		super();
		this.test = test;
		this.ifTrue = ifTrue;
		this.ifFalse = ifFalse;
		this.ifTrue = ifTrue;
		this.ifFalse = ifFalse;
	}
	/** @internal */
	runtimeValue() {
		return this.test.runtimeValue() ? valueOf(this.ifTrue) : valueOf(this.ifFalse);
	}
	toString() {
		return `${this.test} ? ${refOf(this.ifTrue)} : ${refOf(this.ifFalse)}`;
	}
};
/**
* A CEL expression that evaluates to boolean true or false based on a comparison
* between the value of another expression and a literal of that same type.
*/
var CompareExpression = class extends Expression {
	constructor(cmp, lhs, rhs) {
		super();
		this.cmp = cmp;
		this.lhs = lhs;
		this.rhs = rhs;
	}
	/** @internal */
	runtimeValue() {
		const left = valueOf(this.lhs);
		const right = valueOf(this.rhs);
		switch (this.cmp) {
			case "==": return Array.isArray(left) ? this.arrayEquals(left, right) : left === right;
			case "!=": return Array.isArray(left) ? !this.arrayEquals(left, right) : left !== right;
			case ">": return left > right;
			case ">=": return left >= right;
			case "<": return left < right;
			case "<=": return left <= right;
			default: throw new Error(`Unknown comparator ${this.cmp}`);
		}
	}
	/** @internal */
	arrayEquals(a, b) {
		return a.every((item) => b.includes(item)) && b.every((item) => a.includes(item));
	}
	toString() {
		return `${refOf(this.lhs)} ${this.cmp} ${refOf(this.rhs)}`;
	}
	/** Returns a `TernaryExpression` which can resolve to one of two values, based on the resolution of this comparison. */
	thenElse(ifTrue, ifFalse) {
		return new TernaryExpression(this, ifTrue, ifFalse);
	}
};
/** Create a select input from a series of values or a map of labels to values */
function select(options) {
	let wireOpts;
	if (Array.isArray(options)) {
		wireOpts = options.map((opt) => ({ value: opt }));
	} else {
		wireOpts = Object.entries(options).map(([label, value]) => ({
			label,
			value
		}));
	}
	return { select: { options: wireOpts } };
}
/** Create a multi-select input from a series of values or map of labels to values. */
function multiSelect(options) {
	let wireOpts;
	if (Array.isArray(options)) {
		wireOpts = options.map((opt) => ({ value: opt }));
	} else {
		wireOpts = Object.entries(options).map(([label, value]) => ({
			label,
			value
		}));
	}
	return { multiSelect: { options: wireOpts } };
}
/**
* Autogenerate a list of buckets in a project that a user can select from.
*/
const BUCKET_PICKER = { resource: { type: "storage.googleapis.com/Bucket" } };
/**
* Represents a parametrized value that will be read from .env files if present,
* or prompted for by the CLI if missing. Instantiate these with the defineX
* methods exported by the firebase-functions/params namespace.
*/
var Param = class extends Expression {
	static {
		this.type = "string";
	}
	constructor(name, options = {}) {
		super();
		this.name = name;
		this.options = options;
	}
	/** @internal */
	runtimeValue() {
		throw new Error("Not implemented");
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	cmp(cmp, rhs) {
		return new CompareExpression(cmp, this, rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	equals(rhs) {
		return this.cmp("==", rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	notEquals(rhs) {
		return this.cmp("!=", rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	greaterThan(rhs) {
		return this.cmp(">", rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	greaterThanOrEqualTo(rhs) {
		return this.cmp(">=", rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	lessThan(rhs) {
		return this.cmp("<", rhs);
	}
	/** Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression. */
	lessThanOrEqualTo(rhs) {
		return this.cmp("<=", rhs);
	}
	/**
	* Returns a parametrized expression of Boolean type, based on comparing the value of this parameter to a literal or a different expression.
	* @deprecated A typo. Use lessThanOrEqualTo instead.
	*/
	lessThanorEqualTo(rhs) {
		return this.lessThanOrEqualTo(rhs);
	}
	toString() {
		return `params.${this.name}`;
	}
	/** @internal */
	toSpec() {
		const { default: paramDefault,...otherOptions } = this.options;
		const out = {
			name: this.name,
			...otherOptions,
			type: this.constructor.type
		};
		if (paramDefault instanceof Expression) {
			out.default = paramDefault.toCEL();
		} else if (paramDefault !== undefined) {
			out.default = paramDefault;
		}
		if (out.input && "text" in out.input && out.input.text.validationRegex instanceof RegExp) {
			out.input.text.validationRegex = out.input.text.validationRegex.source;
		}
		return out;
	}
};
/**
* A parametrized string whose value is stored in Cloud Secret Manager
* instead of the local filesystem. Supply instances of SecretParams to
* the secrets array while defining a Function to make their values accessible
* during execution of that Function.
*/
var SecretParam = class {
	static {
		this.type = "secret";
	}
	constructor(name, options = {}) {
		this.options = options;
		this.name = name;
	}
	/** @internal */
	runtimeValue() {
		const val = process.env[this.name];
		if (val === undefined) {
			require_logger_index.warn(`No value found for secret parameter "${this.name}". A function can only access a secret if you include the secret in the function's dependency array.`);
		}
		return val || "";
	}
	/** @internal */
	toSpec() {
		return {
			type: "secret",
			name: this.name,
			...this.options
		};
	}
	/** Returns the secret's value at runtime. Throws an error if accessed during deployment. */
	value() {
		if (process.env.FUNCTIONS_CONTROL_API === "true") {
			throw new Error(`Cannot access the value of secret "${this.name}" during function deployment. Secret values are only available at runtime.`);
		}
		return this.runtimeValue();
	}
};
/**
* A parametrized object whose value is stored as a JSON string in Cloud Secret Manager.
* This is useful for managing groups of related configuration values, such as all settings
* for a third-party API, as a single unit. Supply instances of JsonSecretParam to the
* secrets array while defining a Function to make their values accessible during execution
* of that Function.
*/
var JsonSecretParam = class {
	static {
		this.type = "secret";
	}
	constructor(name, options = {}) {
		this.options = options;
		this.name = name;
	}
	/** @internal */
	runtimeValue() {
		const val = process.env[this.name];
		if (val === undefined) {
			throw new Error(`No value found for secret parameter "${this.name}". A function can only access a secret if you include the secret in the function's dependency array.`);
		}
		try {
			return JSON.parse(val);
		} catch (error) {
			throw new Error(`"${this.name}" could not be parsed as JSON. Please verify its value in Secret Manager. Details: ${error}`);
		}
	}
	/** @internal */
	toSpec() {
		return {
			type: "secret",
			name: this.name,
			...this.options,
			format: "json"
		};
	}
	/** Returns the secret's parsed JSON value at runtime. Throws an error if accessed during deployment, if the secret is not set, or if the value is not valid JSON. */
	value() {
		if (process.env.FUNCTIONS_CONTROL_API === "true") {
			throw new Error(`Cannot access the value of secret "${this.name}" during function deployment. Secret values are only available at runtime.`);
		}
		return this.runtimeValue();
	}
};
/**
*  A parametrized value of String type that will be read from .env files
*  if present, or prompted for by the CLI if missing.
*/
var StringParam = class extends Param {
	/** @internal */
	runtimeValue() {
		return process.env[this.name] || "";
	}
};
/**
* A CEL expression which represents an internal Firebase variable. This class
* cannot be instantiated by developers, but we provide several canned instances
* of it to make available parameters that will never have to be defined at
* deployment time, and can always be read from process.env.
* @internal
*/
var InternalExpression = class extends Param {
	constructor(name, getter) {
		super(name);
		this.getter = getter;
	}
	/** @internal */
	runtimeValue() {
		return this.getter(process.env) || "";
	}
	toSpec() {
		throw new Error("An InternalExpression should never be marshalled for wire transmission.");
	}
};
/**
*  A parametrized value of Integer type that will be read from .env files
*  if present, or prompted for by the CLI if missing.
*/
var IntParam = class extends Param {
	static {
		this.type = "int";
	}
	/** @internal */
	runtimeValue() {
		return parseInt(process.env[this.name] || "0", 10) || 0;
	}
};
/**
*  A parametrized value of Float type that will be read from .env files
*  if present, or prompted for by the CLI if missing.
*/
var FloatParam = class extends Param {
	static {
		this.type = "float";
	}
	/** @internal */
	runtimeValue() {
		return parseFloat(process.env[this.name] || "0") || 0;
	}
};
/**
*  A parametrized value of Boolean type that will be read from .env files
*  if present, or prompted for by the CLI if missing.
*/
var BooleanParam = class extends Param {
	static {
		this.type = "boolean";
	}
	/** @internal */
	runtimeValue() {
		return !!process.env[this.name] && process.env[this.name] === "true";
	}
	/** @deprecated */
	then(ifTrue, ifFalse) {
		return this.thenElse(ifTrue, ifFalse);
	}
	thenElse(ifTrue, ifFalse) {
		return new TernaryExpression(this, ifTrue, ifFalse);
	}
};
/**
*  A parametrized value of String[] type that will be read from .env files
*  if present, or prompted for by the CLI if missing.
*/
var ListParam = class extends Param {
	static {
		this.type = "list";
	}
	/** @internal */
	runtimeValue() {
		const val = JSON.parse(process.env[this.name]);
		if (!Array.isArray(val) || !val.every((v) => typeof v === "string")) {
			return [];
		}
		return val;
	}
	/** @hidden */
	greaterThan(rhs) {
		throw new Error(">/< comparison operators not supported on params of type List");
	}
	/** @hidden */
	greaterThanOrEqualTo(rhs) {
		throw new Error(">/< comparison operators not supported on params of type List");
	}
	/** @hidden */
	lessThan(rhs) {
		throw new Error(">/< comparison operators not supported on params of type List");
	}
	/** @hidden */
	lessThanorEqualTo(rhs) {
		throw new Error(">/< comparison operators not supported on params of type List");
	}
};

//#endregion
exports.BUCKET_PICKER = BUCKET_PICKER;
exports.BooleanParam = BooleanParam;
exports.CompareExpression = CompareExpression;
exports.Expression = Expression;
exports.FloatParam = FloatParam;
exports.IntParam = IntParam;
exports.InternalExpression = InternalExpression;
exports.InterpolationExpression = InterpolationExpression;
exports.JsonSecretParam = JsonSecretParam;
exports.ListParam = ListParam;
exports.Param = Param;
exports.SecretParam = SecretParam;
exports.StringParam = StringParam;
exports.TernaryExpression = TernaryExpression;
exports.TransformedStringExpression = TransformedStringExpression;
exports.celOf = celOf;
exports.multiSelect = multiSelect;
exports.select = select;
exports.transform = transform;
exports.valueOf = valueOf;