// Copyright Metatype OÜ, licensed under the Mozilla Public License Version 2.0.
// SPDX-License-Identifier: MPL-2.0
import * as t from "./types.js";
import { core } from "./gen/typegraph_core.js";
import { caller, dirname, fromFileUrl } from "./deps/mod.js";
import { serializeFromParentInjection, serializeGenericInjection, serializeStaticInjection, } from "./utils/injection_utils.js";
import { wit_utils } from "./wit.js";
import { getPolicyChain } from "./types.js";
export class ApplyFromArg {
    constructor(name, type) {
        this.name = name;
        this.type = type;
    }
}
export class ApplyFromStatic {
    constructor(value) {
        this.value = value;
    }
}
export class ApplyFromSecret {
    constructor(key) {
        this.key = key;
    }
}
export class ApplyFromContext {
    constructor(key, type) {
        this.key = key;
        this.type = type;
    }
}
export class ApplyFromParent {
    constructor(typeName) {
        this.typeName = typeName;
    }
}
const InjectionSource = {
    asArg: (name, type) => { var _a; return new ApplyFromArg(name !== null && name !== void 0 ? name : null, (_a = type === null || type === void 0 ? void 0 : type._id) !== null && _a !== void 0 ? _a : null); },
    set: (value) => new ApplyFromStatic(value),
    fromSecret: (key) => new ApplyFromSecret(key),
    fromContext: (key, type) => { var _a; return new ApplyFromContext(key, (_a = type === null || type === void 0 ? void 0 : type._id) !== null && _a !== void 0 ? _a : null); },
    fromParent: (typeName) => new ApplyFromParent(typeName),
};
export class InheritDef {
    set(value) {
        this.payload = serializeStaticInjection(value);
        return this;
    }
    inject(value) {
        this.payload = serializeGenericInjection("dynamic", value);
        return this;
    }
    fromContext(value) {
        this.payload = serializeGenericInjection("context", value);
        return this;
    }
    fromSecret(value) {
        this.payload = serializeGenericInjection("secret", value);
        return this;
    }
    fromParent(value) {
        this.payload = serializeFromParentInjection(value);
        return this;
    }
    fromRandom() {
        this.payload = serializeGenericInjection("random", null);
        return this;
    }
}
export class RawAuth {
    constructor(jsonStr) {
        this.jsonStr = jsonStr;
    }
}
export function typegraph(nameOrArgs, maybeBuilder) {
    const args = typeof nameOrArgs === "string"
        ? { name: nameOrArgs }
        : nameOrArgs;
    const { name, dynamic, cors, prefix, rate, secrets, disableAutoSerialization, } = args;
    const builder = "builder" in args
        ? args.builder
        : maybeBuilder;
    const file = caller();
    if (!file) {
        throw new Error("Could not determine caller file");
    }
    // node/deno compat tick until MET-236 is landed
    const simpleFile = file.replace(/:[0-9]+$/, "").replace(/^file:\/\//, "");
    const path = dirname(fromFileUrl(`file://${simpleFile}`));
    const defaultCorsFields = {
        allowCredentials: true,
        allowHeaders: [],
        allowMethods: [],
        allowOrigin: [],
        exposeHeaders: [],
        maxAgeSec: undefined,
    };
    const defaultRateFields = {
        localExcess: 0,
    };
    const tgParams = {
        prefix,
        secrets: secrets !== null && secrets !== void 0 ? secrets : [],
        cors: cors ? { ...defaultCorsFields, ...cors } : defaultCorsFields,
        rate: rate ? { ...defaultRateFields, ...rate } : undefined,
    };
    core.initTypegraph({ name, dynamic, path, ...tgParams });
    const g = {
        expose: (exports, defaultPolicy) => {
            core.expose(Object.entries(exports).map(([name, fn]) => [name, fn._id]), defaultPolicy ? getPolicyChain(defaultPolicy) : []);
        },
        inherit: () => {
            return new InheritDef();
        },
        rest: (graphql) => {
            return wit_utils.addGraphqlEndpoint(graphql);
        },
        auth: (value) => {
            if (value instanceof RawAuth) {
                return wit_utils.addRawAuth(value.jsonStr);
            }
            return wit_utils.addAuth(value);
        },
        ref: (name) => {
            return genRef(name);
        },
        configureRandomInjection: (params) => {
            return core.setSeed(params.seed);
        },
        ...InjectionSource,
    };
    builder(g);
    let serialize = () => "";
    if (!disableAutoSerialization) {
        const tgJson = core.finalizeTypegraph({ tag: "simple" });
        console.log(tgJson);
        serialize = () => tgJson;
    }
    else {
        // config is known at deploy time
        serialize = (config) => {
            const tgJson = core.finalizeTypegraph({
                tag: "resolve-artifacts",
                val: config,
            });
            return tgJson;
        };
    }
    return {
        serialize,
        name,
    };
}
export function genRef(name) {
    const value = core.refb(name, []);
    if (typeof value == "object") {
        throw new Error(JSON.stringify(value));
    }
    return new t.Typedef(value, { name });
}
