import type { ActionFunctionArgs } from "@remix-run/server-runtime";
import { json } from "@remix-run/server-runtime";
import { z } from "zod";
import { prisma } from "~/db.server";
import { requireAdminApiRequest } from "~/services/personalAccessToken.server";
import { controlPlaneResolver } from "~/v3/runOpsMigration/controlPlaneResolver.server";
import { updateEnvConcurrencyLimits } from "~/v3/runQueue.server";

const ParamsSchema = z.object({
  organizationId: z.string(),
});

const RequestBodySchema = z.object({
  organization: z.number(),
  development: z.number().optional(),
  staging: z.number().optional(),
  production: z.number().optional(),
});

export async function action({ request, params }: ActionFunctionArgs) {
  await requireAdminApiRequest(request);

  const { organizationId } = ParamsSchema.parse(params);

  const rawBody = await request.json();
  const body = RequestBodySchema.parse(rawBody);

  if (!body.development && !body.staging && !body.production) {
    return json({ error: "At least one environment limit must be provided" }, { status: 400 });
  }

  //update org
  const organization = await prisma.organization.update({
    where: {
      id: organizationId,
    },
    data: {
      maximumConcurrencyLimit: body.organization,
    },
  });

  //update environments
  const environments = await prisma.runtimeEnvironment.findMany({
    where: {
      organizationId: organizationId,
      project: {
        version: "V3",
      },
    },
  });

  for (const environment of environments) {
    let limit: number | undefined = undefined;
    switch (environment.type) {
      case "DEVELOPMENT": {
        limit = body.development;
        break;
      }
      case "PREVIEW":
      case "STAGING": {
        limit = body.staging;
        break;
      }
      case "PRODUCTION": {
        limit = body.production;
        break;
      }
    }

    if (!limit) continue;

    const modifiedEnvironment = await prisma.runtimeEnvironment.update({
      where: {
        id: environment.id,
      },
      data: {
        maximumConcurrencyLimit: limit,
      },
      include: {
        project: true,
      },
    });

    await updateEnvConcurrencyLimits({ ...modifiedEnvironment, organization });
  }

  // Org + every affected env's concurrency changed; one org invalidation covers them all.
  controlPlaneResolver.invalidateOrganization(organizationId);

  return json({ success: true });
}
