import { parseUnlinkAttachmentIds } from "../../../commands/attachments.js";
import { Message, MessageRecipient } from "../../../data/entities.js";
import { attachmentIdsPayloadSchema, unlinkAttachmentPayloadSchema } from "../../../data/validators.js";
import { getMessageAttachments } from "../../../lib/attachments.js";
import { attachOperationMetadataHeader } from "../../../lib/operationMetadata.js";
import { resolveMessageContext } from "../../../lib/routeHelpers.js";
import { resolveUserFeatures, runMessageMutationGuardAfterSuccess, runMessageMutationGuards } from "../../guards.js";
import {
  attachmentIdsPayloadSchema as attachmentIdsOpenApiSchema,
  errorResponseSchema,
  messageAttachmentResponseSchema,
  okResponseSchema,
  unlinkAttachmentPayloadSchema as unlinkAttachmentOpenApiSchema
} from "../../openapi.js";
const metadata = {
  GET: { requireAuth: true },
  POST: { requireAuth: true, requireFeatures: ["messages.attach_files"] },
  DELETE: { requireAuth: true, requireFeatures: ["messages.attach_files"] }
};
function hasOrganizationAccess(scopeOrganizationId, messageOrganizationId) {
  if (scopeOrganizationId) {
    return messageOrganizationId === scopeOrganizationId;
  }
  return messageOrganizationId == null;
}
async function GET(req, { params }) {
  const { ctx, scope } = await resolveMessageContext(req);
  const em = ctx.container.resolve("em");
  const message = await em.findOne(Message, {
    id: params.id,
    tenantId: scope.tenantId,
    deletedAt: null
  });
  if (!message) {
    return Response.json({ error: "Message not found" }, { status: 404 });
  }
  if (!hasOrganizationAccess(scope.organizationId, message.organizationId)) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  const recipient = await em.findOne(MessageRecipient, {
    messageId: params.id,
    recipientUserId: scope.userId,
    deletedAt: null
  });
  if (message.senderUserId !== scope.userId && !recipient) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  const attachments = await getMessageAttachments(
    em,
    params.id,
    scope.organizationId,
    scope.tenantId
  );
  return Response.json({ attachments });
}
async function POST(req, { params }) {
  const { ctx, scope } = await resolveMessageContext(req);
  const em = ctx.container.resolve("em").fork();
  const body = await req.json().catch(() => ({}));
  const input = attachmentIdsPayloadSchema.parse(body);
  const message = await em.findOne(Message, {
    id: params.id,
    tenantId: scope.tenantId,
    deletedAt: null
  });
  if (!message) {
    return Response.json({ error: "Message not found" }, { status: 404 });
  }
  if (!hasOrganizationAccess(scope.organizationId, message.organizationId)) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  if (message.senderUserId !== scope.userId) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  if (!message.isDraft) {
    return Response.json({ error: "Attachments can only be modified on drafts" }, { status: 409 });
  }
  const commandBus = ctx.container.resolve("commandBus");
  const guardResult = await runMessageMutationGuards(
    ctx.container,
    {
      tenantId: scope.tenantId,
      organizationId: scope.organizationId,
      userId: scope.userId,
      resourceKind: "messages.message",
      resourceId: message.id,
      operation: "update",
      requestMethod: req.method,
      requestHeaders: req.headers,
      mutationPayload: input
    },
    resolveUserFeatures(ctx.auth)
  );
  if (!guardResult.ok) {
    return Response.json(
      guardResult.errorBody ?? { error: "Operation blocked by guard" },
      { status: guardResult.errorStatus ?? 422 }
    );
  }
  const { logEntry } = await commandBus.execute("messages.attachments.link_to_draft", {
    input: {
      messageId: message.id,
      tenantId: scope.tenantId,
      organizationId: scope.organizationId,
      userId: scope.userId,
      attachmentIds: input.attachmentIds
    },
    ctx: {
      container: ctx.container,
      auth: ctx.auth ?? null,
      organizationScope: null,
      selectedOrganizationId: scope.organizationId,
      organizationIds: scope.organizationId ? [scope.organizationId] : null,
      request: req
    }
  });
  const response = Response.json({ ok: true });
  attachOperationMetadataHeader(response, logEntry, {
    resourceKind: "messages.message",
    resourceId: params.id
  });
  await runMessageMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
    tenantId: scope.tenantId,
    organizationId: scope.organizationId,
    userId: scope.userId,
    resourceKind: "messages.message",
    resourceId: message.id,
    operation: "update",
    requestMethod: req.method,
    requestHeaders: req.headers
  });
  return response;
}
async function DELETE(req, { params }) {
  const { ctx, scope } = await resolveMessageContext(req);
  const em = ctx.container.resolve("em").fork();
  const body = await req.json().catch(() => ({}));
  const input = unlinkAttachmentPayloadSchema.parse(body);
  const message = await em.findOne(Message, {
    id: params.id,
    tenantId: scope.tenantId,
    deletedAt: null
  });
  if (!message) {
    return Response.json({ error: "Message not found" }, { status: 404 });
  }
  if (!hasOrganizationAccess(scope.organizationId, message.organizationId)) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  if (message.senderUserId !== scope.userId) {
    return Response.json({ error: "Access denied" }, { status: 403 });
  }
  if (!message.isDraft) {
    return Response.json({ error: "Attachments can only be modified on drafts" }, { status: 409 });
  }
  const commandBus = ctx.container.resolve("commandBus");
  const guardResult = await runMessageMutationGuards(
    ctx.container,
    {
      tenantId: scope.tenantId,
      organizationId: scope.organizationId,
      userId: scope.userId,
      resourceKind: "messages.message",
      resourceId: message.id,
      operation: "update",
      requestMethod: req.method,
      requestHeaders: req.headers,
      mutationPayload: input
    },
    resolveUserFeatures(ctx.auth)
  );
  if (!guardResult.ok) {
    return Response.json(
      guardResult.errorBody ?? { error: "Operation blocked by guard" },
      { status: guardResult.errorStatus ?? 422 }
    );
  }
  const { logEntry } = await commandBus.execute("messages.attachments.unlink_from_draft", {
    input: {
      messageId: message.id,
      tenantId: scope.tenantId,
      organizationId: scope.organizationId,
      userId: scope.userId,
      attachmentIds: parseUnlinkAttachmentIds(input)
    },
    ctx: {
      container: ctx.container,
      auth: ctx.auth ?? null,
      organizationScope: null,
      selectedOrganizationId: scope.organizationId,
      organizationIds: scope.organizationId ? [scope.organizationId] : null,
      request: req
    }
  });
  const response = Response.json({ ok: true });
  attachOperationMetadataHeader(response, logEntry, {
    resourceKind: "messages.message",
    resourceId: params.id
  });
  await runMessageMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
    tenantId: scope.tenantId,
    organizationId: scope.organizationId,
    userId: scope.userId,
    resourceKind: "messages.message",
    resourceId: message.id,
    operation: "update",
    requestMethod: req.method,
    requestHeaders: req.headers
  });
  return response;
}
const openApi = {
  tag: "Messages",
  methods: {
    GET: {
      summary: "List message attachments",
      responses: [
        { status: 200, description: "Attachments", schema: messageAttachmentResponseSchema }
      ],
      errors: [
        { status: 403, description: "Access denied", schema: errorResponseSchema },
        { status: 404, description: "Message not found", schema: errorResponseSchema }
      ]
    },
    POST: {
      summary: "Link attachments to draft message",
      requestBody: { schema: attachmentIdsOpenApiSchema },
      responses: [
        { status: 200, description: "Attachments linked", schema: okResponseSchema }
      ],
      errors: [
        { status: 403, description: "Access denied", schema: errorResponseSchema },
        { status: 404, description: "Message not found", schema: errorResponseSchema },
        { status: 409, description: "Only draft messages can be edited", schema: errorResponseSchema }
      ]
    },
    DELETE: {
      summary: "Unlink attachments from draft message",
      requestBody: { schema: unlinkAttachmentOpenApiSchema },
      responses: [
        { status: 200, description: "Attachments unlinked", schema: okResponseSchema }
      ],
      errors: [
        { status: 403, description: "Access denied", schema: errorResponseSchema },
        { status: 404, description: "Message not found", schema: errorResponseSchema },
        { status: 409, description: "Only draft messages can be edited", schema: errorResponseSchema }
      ]
    }
  }
};
export {
  DELETE,
  GET,
  POST,
  metadata,
  openApi
};
//# sourceMappingURL=route.js.map
