import { type ActionFunctionArgs, json } from "@remix-run/server-runtime";
import {
  type CreateArtifactResponseBody,
  CreateArtifactRequestBody,
  tryCatch,
} from "@trigger.dev/core/v3";
import { authenticateRequest } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { ArtifactsService } from "~/v3/services/artifacts.server";

export async function action({ request }: ActionFunctionArgs) {
  if (request.method.toUpperCase() !== "POST") {
    return json({ error: "Method Not Allowed" }, { status: 405 });
  }

  try {
    const authenticationResult = await authenticateRequest(request, {
      apiKey: true,
      organizationAccessToken: false,
      personalAccessToken: false,
    });

    if (!authenticationResult || !authenticationResult.result.ok) {
      logger.info("Invalid or missing api key", { url: request.url });
      return json({ error: "Invalid or Missing API key" }, { status: 401 });
    }

    const [, rawBody] = await tryCatch(request.json());
    const body = CreateArtifactRequestBody.safeParse(rawBody ?? {});

    if (!body.success) {
      return json({ error: "Invalid request body", issues: body.error.issues }, { status: 400 });
    }

    const { environment: authenticatedEnv } = authenticationResult.result;

    const service = new ArtifactsService();
    return await service
      .createArtifact(body.data.type, authenticatedEnv, body.data.contentLength)
      .match(
        (result) => {
          return json(
            {
              artifactKey: result.artifactKey,
              uploadUrl: result.uploadUrl,
              uploadFields: result.uploadFields,
              expiresAt: result.expiresAt.toISOString(),
            } satisfies CreateArtifactResponseBody,
            { status: 201 }
          );
        },
        (error) => {
          switch (error.type) {
            case "artifact_size_exceeds_limit": {
              logger.warn("Artifact size exceeds limit", { error });
              const sizeMB = parseFloat((error.contentLength / (1024 * 1024)).toFixed(1));
              const limitMB = parseFloat((error.sizeLimit / (1024 * 1024)).toFixed(1));

              let errorMessage;

              switch (body.data.type) {
                case "deployment_context":
                  errorMessage = `Artifact size (${sizeMB} MB) exceeds the allowed limit of ${limitMB} MB. Make sure you are in the correct directory of your Trigger.dev project. Reach out to us if you are seeing this error consistently.`;
                  break;
                default:
                  body.data.type satisfies never;
                  errorMessage = `Artifact size (${sizeMB} MB) exceeds the allowed limit of ${limitMB} MB`;
              }
              return json(
                {
                  error: errorMessage,
                },
                { status: 400 }
              );
            }
            case "failed_to_create_presigned_post": {
              logger.error("Failed to create presigned POST", { error });
              return json({ error: "Failed to generate artifact upload URL" }, { status: 500 });
            }
            case "artifacts_bucket_not_configured": {
              logger.error("Artifacts bucket not configured", { error });
              return json({ error: "Internal server error" }, { status: 500 });
            }
            default: {
              error satisfies never;
              logger.error("Failed creating artifact", { error });
              return json({ error: "Internal server error" }, { status: 500 });
            }
          }
        }
      );
  } catch (error) {
    if (error instanceof Response) throw error;
    logger.error("Failed to create artifact", { error });
    return json({ error: "Internal Server Error" }, { status: 500 });
  }
}
