import { Resource } from "sst";
import type { SQSHandler } from "aws-lambda";
import {
    SQSClient,
    SendMessageCommand
} from "@aws-sdk/client-sqs";
import {
    LambdaClient,
    InvokeCommand,
    GetFunctionCommand,
    ResourceNotFoundException,
} from "@aws-sdk/client-lambda";

const lambda = new LambdaClient({});
lambda.middlewareStack.remove("recursionDetectionMiddleware");
const sqs = new SQSClient({});
sqs.middlewareStack.remove("recursionDetectionMiddleware");

export const handler: SQSHandler = async (evt) => {
    for (const record of evt.Records) {
    const parsed = JSON.parse(record.body);
    console.log("body", parsed);
    const functionName = parsed.requestContext.functionArn
      .replace(":$LATEST", "")
      .split(":")
      .pop();
    if (parsed.responsePayload) {
      const attempt = (parsed.requestPayload.attempts || 0) + 1;

      const info = await lambda.send(
        new GetFunctionCommand({
          FunctionName: functionName,
        }),
      );
      const max =
        Number.parseInt(
          info.Configuration?.Environment?.Variables?.RETRIES || "",
        ) || 0;
      console.log("max retries", max);
      if (attempt > max) {
        console.log(`giving up after ${attempt} retries`);
        // send to dlq
        await sqs.send(
          new SendMessageCommand({
            QueueUrl: Resource.Dlq.url,
            MessageBody: JSON.stringify({
              requestPayload: parsed.requestPayload,
              requestContext: parsed.requestContext,
              responsePayload: parsed.responsePayload,
            }),
          }),
        );
        return;
      }
      const seconds = Math.min(Math.pow(2, attempt), 900);
      console.log(
        "delaying retry by ",
        seconds,
        "seconds for attempt",
        attempt,
      );
      parsed.requestPayload.attempts = attempt;
      await sqs.send(
        new SendMessageCommand({
          QueueUrl: Resource.RetryQueue.url,
          DelaySeconds: seconds,
          MessageBody: JSON.stringify({
            requestPayload: parsed.requestPayload,
            requestContext: parsed.requestContext,
          }),
        }),
      );
    }

    if (!parsed.responsePayload) {
      console.log("triggering function");
      try {
        await lambda.send(
          new InvokeCommand({
            InvocationType: "Event",
            Payload: Buffer.from(JSON.stringify(parsed.requestPayload)),
            FunctionName: functionName,
          }),
        );
      } catch (e) {
        if (e instanceof ResourceNotFoundException) {
          return;
        }
        throw e;
      }
    }
  }
}