import { type ActionFunction } from "@remix-run/node";
import { prisma } from "~/db.server";
import { jsonWithErrorMessage, jsonWithSuccessMessage } from "~/models/message.server";
import { logger } from "~/services/logger.server";
import { requireUserId } from "~/services/session.server";
import { v3RunParamsSchema } from "~/utils/pathBuilder";
import { runStore } from "~/v3/runStore.server";
import { ResetIdempotencyKeyService } from "~/v3/services/resetIdempotencyKey.server";

export const action: ActionFunction = async ({ request, params }) => {
  const userId = await requireUserId(request);
  const { projectParam, organizationSlug, envParam, runParam } = v3RunParamsSchema.parse(params);

  try {
    const taskRun = await runStore.findRun(
      {
        friendlyId: runParam,
      },
      {
        select: {
          id: true,
          idempotencyKey: true,
          taskIdentifier: true,
          projectId: true,
          runtimeEnvironmentId: true,
        },
      }
    );

    if (!taskRun) {
      return jsonWithErrorMessage({}, request, "Run not found");
    }

    const authorizedProject = await prisma.project.findFirst({
      where: { id: taskRun.projectId, organization: { members: { some: { userId } } } },
      select: { id: true },
    });

    if (!authorizedProject) {
      return jsonWithErrorMessage({}, request, "Run not found");
    }

    if (!taskRun.idempotencyKey) {
      return jsonWithErrorMessage({}, request, "This run does not have an idempotency key");
    }

    const environment = await prisma.runtimeEnvironment.findFirst({
      where: {
        id: taskRun.runtimeEnvironmentId,
      },
      include: {
        project: {
          include: {
            organization: true,
          },
        },
      },
    });

    if (!environment) {
      return jsonWithErrorMessage({}, request, "Environment not found");
    }

    if (
      environment.slug !== envParam ||
      environment.project.slug !== projectParam ||
      environment.project.organization.slug !== organizationSlug
    ) {
      return jsonWithErrorMessage({}, request, "Run not found");
    }

    const service = new ResetIdempotencyKeyService();

    await service.call(taskRun.idempotencyKey, taskRun.taskIdentifier, {
      ...environment,
      organizationId: environment.project.organizationId,
      organization: environment.project.organization,
    });

    return jsonWithSuccessMessage({}, request, "Idempotency key reset successfully");
  } catch (error) {
    if (error instanceof Error) {
      logger.error("Failed to reset idempotency key", {
        error: {
          name: error.name,
          message: error.message,
          stack: error.stack,
        },
      });
      return jsonWithErrorMessage({}, request, `Failed to reset idempotency key: ${error.message}`);
    } else {
      logger.error("Failed to reset idempotency key", { error });
      return jsonWithErrorMessage(
        {},
        request,
        `Failed to reset idempotency key: ${JSON.stringify(error)}`
      );
    }
  }
};
