// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0.
// SPDX-License-Identifier: MPL-2.0
import "../_dnt.polyfills.js";
import * as t from "../types.js";
import { runtimes } from "../wit.js";
import Policy from "../policy.js";
import { Runtime } from "./mod.js";
import { fx } from "../index.js";
// deno-lint-ignore no-explicit-any
function stringifyFn(code) {
    if (typeof code == "function") {
        const source = code.toString();
        const namedFnMatch = source.match(/function\s*(\*?\s*[a-zA-Z0-9_]+)/);
        if (namedFnMatch) {
            const [, name] = namedFnMatch;
            if (name.replace(/\s/g, "").startsWith("*")) {
                throw new Error(`Generator function "${name}" not supported`);
            }
            if (/function\s[a-zA-Z0-9_]+\(\) { \[native code\] }/.test(source)) {
                throw new Error(`"${name}" is not supported as it is a native function`);
            }
        }
        return source;
    }
    return code;
}
export class DenoRuntime extends Runtime {
    constructor() {
        super(runtimes.getDenoRuntime());
    }
    func(inp, out, { code, secrets = [], effect = fx.read() }) {
        const source = stringifyFn(code);
        const matId = runtimes.registerDenoFunc({ code: source, secrets }, effect);
        const mat = {
            _id: matId,
            code: source,
            secrets,
            effect,
        };
        return t.func(inp, out, mat);
    }
    import(inp, out, { name, module, deps = [], effect = fx.read(), secrets = [] }) {
        const matId = runtimes.importDenoFunction({
            funcName: name,
            module,
            deps,
            secrets,
        }, effect);
        const mat = {
            _id: matId,
            name,
            module,
            secrets,
            effect,
        };
        return t.func(inp, out, mat);
    }
    identity(inp) {
        const mat = {
            _id: runtimes.getPredefinedDenoFunc({ name: "identity" }),
            name: "identity",
        };
        return t.func(inp, inp, mat);
    }
    /** use a static function already registered on the typegate */
    // deno-lint-ignore no-explicit-any
    static(out, value) {
        const mat = {
            _id: runtimes.registerDenoStatic({
                value: JSON.stringify(value),
            }, out._id),
        };
        return t.func(t.struct({}), out, mat);
    }
    /** Utility for fetching the current request context */
    fetchContext(outputShape) {
        const returnValue = outputShape ? `context` : "JSON.stringify(context)";
        return this.func(t.struct({}), outputShape ?? t.json(), { code: `(_, { context }) => ${returnValue}` });
    }
    policy(name, data) {
        const params = typeof data === "string"
            ? { code: data, secrets: [] }
            : { secrets: [], ...data };
        return Policy.create(name, runtimes.registerDenoFunc({ ...params, code: stringifyFn(params.code) }, fx.read()));
    }
    importPolicy(data, name) {
        const policyName = name ??
            `__imp_${data.module}_${data.name}`.replace(/[^a-zA-Z0-9_]/g, "_");
        return Policy.create(policyName, runtimes.importDenoFunction({
            funcName: data.name,
            module: data.module,
            secrets: data.secrets ?? [],
            deps: data.deps ?? [],
        }, fx.read()));
    }
}
