import { json } from "@remix-run/server-runtime";
import { z } from "zod";
import { prisma } from "~/db.server";
import { createMultiMethodApiRoute } from "~/services/routeBuilders/apiBuilder.server";
import { ServiceValidationError } from "~/v3/services/baseService.server";
import { PromptService } from "~/v3/services/promptService.server";

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

const CreateBody = z.object({
  textContent: z.string(),
  model: z.string().optional(),
  commitMessage: z.string().optional(),
  // `code` is reserved for deploy-created versions.
  source: z
    .string()
    .refine((source) => source !== "code")
    .optional(),
});

const UpdateBody = z.object({
  textContent: z.string().optional(),
  model: z.string().optional(),
  commitMessage: z.string().optional(),
});

async function findPrompt(
  slug: string,
  authentication: { environment: { projectId: string; id: string } }
) {
  return prisma.prompt.findUnique({
    where: {
      projectId_runtimeEnvironmentId_slug: {
        projectId: authentication.environment.projectId,
        runtimeEnvironmentId: authentication.environment.id,
        slug,
      },
    },
  });
}

const { action, loader } = createMultiMethodApiRoute({
  params: ParamsSchema,
  allowJWT: true,
  corsStrategy: "all",
  authorization: {
    action: "update",
    resource: (params) => ({ type: "prompts", id: params.slug }),
  },
  methods: {
    POST: {
      body: CreateBody,
      handler: async ({ params, body, authentication }) => {
        const prompt = await findPrompt(params.slug, authentication);
        if (!prompt) return json({ error: "Prompt not found" }, { status: 404 });

        const service = new PromptService();
        const result = await service.createOverride(prompt.id, {
          textContent: body.textContent,
          model: body.model,
          commitMessage: body.commitMessage,
          source: body.source ?? "api",
        });

        return json({ ok: true, version: result.version });
      },
    },
    PUT: {
      body: UpdateBody,
      handler: async ({ params, body, authentication }) => {
        const prompt = await findPrompt(params.slug, authentication);
        if (!prompt) return json({ error: "Prompt not found" }, { status: 404 });

        try {
          const service = new PromptService();
          await service.updateOverride(prompt.id, body);
        } catch (e) {
          if (e instanceof ServiceValidationError) {
            return json({ error: e.message }, { status: e.status ?? 400 });
          }
          throw e;
        }

        return json({ ok: true });
      },
    },
    PATCH: {
      body: UpdateBody,
      handler: async ({ params, body, authentication }) => {
        const prompt = await findPrompt(params.slug, authentication);
        if (!prompt) return json({ error: "Prompt not found" }, { status: 404 });

        try {
          const service = new PromptService();
          await service.updateOverride(prompt.id, body);
        } catch (e) {
          if (e instanceof ServiceValidationError) {
            return json({ error: e.message }, { status: e.status ?? 400 });
          }
          throw e;
        }

        return json({ ok: true });
      },
    },
    DELETE: {
      handler: async ({ params, authentication }) => {
        const prompt = await findPrompt(params.slug, authentication);
        if (!prompt) return json({ error: "Prompt not found" }, { status: 404 });

        const service = new PromptService();
        await service.removeOverride(prompt.id);
        return json({ ok: true });
      },
    },
  },
});

export { action, loader };
