import { isNullType, isTemplateDeclaration, isTemplateInstance, } from "@typespec/compiler";
/** Acts as a cache for processing inputs.
 *
 * If the input is undefined, the output is always undefined.
 * for a given input, the process is only ever called once.
 *
 *
 */
export class ProcessingCache {
    constructor(transform) {
        this.transform = transform;
        this.results = new Map();
    }
    has(original) {
        return !!original && !!this.results.get(original);
    }
    set(original, result) {
        this.results.set(original, result);
        return result;
    }
    process(original, ...args) {
        if (original) {
            const result = this.results.get(original) || this.transform(original, ...args);
            this.results.set(original, result);
            return result;
        }
        return undefined;
    }
}
/** adds only if the item is not in the collection already
 *
 * @note  While this isn't very efficient, it doesn't disturb the original
 * collection, so you won't get inadvertent side effects from using Set, etc.
 */
export function pushDistinct(targetArray, ...items) {
    for (const i of items) {
        if (!targetArray.includes(i)) {
            targetArray.push(i);
        }
    }
    return targetArray;
}
export function modelContainsDerivedModel(model) {
    return !isTemplateDeclaration(model) && !(isTemplateInstance(model) && model.derivedModels.length === 0);
}
export function isModelReferredInTemplate(template, target) {
    var _a, _b, _c;
    return (template === target ||
        ((_c = (_b = (_a = template === null || template === void 0 ? void 0 : template.templateMapper) === null || _a === void 0 ? void 0 : _a.args) === null || _b === void 0 ? void 0 : _b.some((it) => it.kind === "Model" || it.kind === "Union" ? isModelReferredInTemplate(it, target) : false)) !== null && _c !== void 0 ? _c : false));
}
export function getNameForTemplate(target) {
    switch (target.kind) {
        case "Model": {
            let name = target.name;
            if (target.templateMapper && target.templateMapper.args) {
                name = name + target.templateMapper.args.map((it) => getNameForTemplate(it)).join("");
            }
            return name;
        }
        case "String":
            return target.value;
        default:
            return "";
    }
}
export function isNullableType(type) {
    if (type.kind === "Union") {
        const nullVariants = Array.from(type.variants.values()).filter((it) => isNullType(it.type));
        return nullVariants.length >= 1;
    }
    else {
        return false;
    }
}
export function isSameLiteralTypes(variants) {
    const kindSet = new Set(variants.map((it) => it.type.kind));
    if (kindSet.size === 1) {
        const kind = kindSet.values().next().value;
        return kind === "String" || kind === "Number" || kind === "Boolean";
    }
    else {
        return false;
    }
}
export function getDurationFormat(encode) {
    let format = "duration-rfc3339";
    // duration encoded as seconds
    if (encode.encoding === "seconds") {
        const scalarName = encode.type.name;
        if (scalarName.startsWith("int") || scalarName.startsWith("uint") || scalarName === "safeint") {
            format = "seconds-integer";
        }
        else if (scalarName.startsWith("float")) {
            format = "seconds-number";
        }
        else {
            throw new Error(`Unrecognized scalar type used by duration encoded as seconds: '${scalarName}'.`);
        }
    }
    return format;
}
export function hasScalarAsBase(type, scalarName) {
    let scalarType = type;
    while (scalarType) {
        if (scalarType.name === scalarName) {
            return true;
        }
        scalarType = scalarType.baseScalar;
    }
    return false;
}
//# sourceMappingURL=type-utils.js.map