import { decodeQueueDescriptor } from "../shared/queue-descriptor";
import { UsageMeter } from "../shared/usage-meter";
import fetch from "node-fetch";
import { TokenRepo } from "../shared/token-repo";
import { asymmetric, symmetric } from "secure-webhooks";
import { Telemetrist } from "../shared/telemetrist";
import { createOwl } from "../shared/owl";
import { ssrfFilter } from "./ssrf-filter";
import { PostHog } from "posthog-node";
export function replaceLocalhostWithDockerHost(_url) {
    const url = new URL(_url);
    if (url.hostname === "localhost") {
        url.hostname = "host.docker.internal";
    }
    return url.toString();
}
export async function createWorker({ redisFactory, enableUsageMetering, runningInDocker, concurrency = 100, disableTelemetry, logger, incidentReceiver, webhookSigningPrivateKey, enableSSRFPrevention, postHogApiKey, }) {
    const redisClient = redisFactory();
    const telemetrist = disableTelemetry
        ? undefined
        : new Telemetrist(runningInDocker !== null && runningInDocker !== void 0 ? runningInDocker : false);
    const tokenRepo = webhookSigningPrivateKey
        ? undefined
        : new TokenRepo(redisClient);
    let usageMeter = undefined;
    if (enableUsageMetering) {
        usageMeter = new UsageMeter(redisClient);
    }
    let postHog = undefined;
    if (postHogApiKey) {
        postHog = new PostHog(postHogApiKey, {
            host: "https://app.posthog.com",
        });
    }
    const owl = await createOwl(redisFactory, logger, incidentReceiver, telemetrist);
    const worker = await owl.createWorker(async (job, ack, span) => {
        let { tokenId, endpoint } = decodeQueueDescriptor(job.queue);
        const body = job.payload;
        const executionDone = logger === null || logger === void 0 ? void 0 : logger.startingExecution({
            tokenId,
            endpoint,
            body,
            id: job.id,
        });
        const headers = {
            "Content-Type": "text/plain",
            "x-quirrel-meta": JSON.stringify({
                id: job.id,
                count: job.count,
                exclusive: job.exclusive,
                retry: job.retry,
                nextRepetition: ack.nextExecutionDate,
            }),
        };
        if (tokenId) {
            const payload = body !== null && body !== void 0 ? body : "";
            if (webhookSigningPrivateKey) {
                headers["x-quirrel-signature"] = asymmetric.sign(payload, webhookSigningPrivateKey);
            }
            else {
                const token = await (tokenRepo === null || tokenRepo === void 0 ? void 0 : tokenRepo.getById(tokenId));
                if (token) {
                    headers["x-quirrel-signature"] = symmetric.sign(payload, token);
                }
            }
        }
        if (runningInDocker) {
            endpoint = replaceLocalhostWithDockerHost(endpoint);
        }
        const [response] = await Promise.all([
            fetch(endpoint, {
                method: "POST",
                body,
                headers,
                agent: enableSSRFPrevention ? ssrfFilter : undefined,
            }),
            usageMeter === null || usageMeter === void 0 ? void 0 : usageMeter.record(tokenId),
        ]);
        postHog === null || postHog === void 0 ? void 0 : postHog.capture({
            distinctId: tokenId,
            event: "job executed",
            properties: {
                endpoint,
                status: response.status,
            },
        });
        if (response.status >= 200 && response.status < 300) {
            executionDone === null || executionDone === void 0 ? void 0 : executionDone();
            telemetrist === null || telemetrist === void 0 ? void 0 : telemetrist.dispatch("dispatch_job");
            await worker.acknowledger.acknowledge(ack, undefined, span);
        }
        else {
            const responseBody = await response.text();
            const error = {
                tokenId,
                endpoint,
                responseBody,
                responseStatus: response.status,
                toString() {
                    return responseBody;
                },
            };
            await worker.acknowledger.reportFailure(ack, job, error, {
                dontReschedule: response.status === 404,
            });
        }
    });
    async function close() {
        postHog === null || postHog === void 0 ? void 0 : postHog.shutdown();
        await worker.close();
        await redisClient.quit();
    }
    return {
        close,
    };
}
//# sourceMappingURL=index.js.map