import { NextResponse } from "next/server";
import { z } from "zod";
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
import { Attachment, AttachmentPartition } from "../../../data/entities.js";
import {
  mergeAttachmentMetadata,
  normalizeAttachmentAssignments,
  normalizeAttachmentTags,
  readAttachmentMetadata
} from "../../../lib/metadata.js";
import { splitCustomFieldPayload, loadCustomFieldValues } from "@open-mercato/shared/lib/crud/custom-fields";
import { emitCrudSideEffects, setCustomFieldsIfAny } from "@open-mercato/shared/lib/commands/helpers";
import { normalizeCustomFieldResponse } from "@open-mercato/shared/lib/custom-fields/normalize";
import { E } from "../../../../../generated/entities.ids.generated.js";
import { attachmentCrudEvents, attachmentCrudIndexer } from "../../../lib/crud.js";
import { applyAssignmentEnrichments, resolveAssignmentEnrichments } from "../../../lib/assignmentDetails.js";
import {
  attachmentsTag,
  attachmentDetailResponseSchema,
  attachmentErrorSchema
} from "../../openapi.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("attachments").child({ component: "library" });
const updateSchema = z.object({
  tags: z.array(z.string()).optional(),
  assignments: z.array(
    z.object({
      type: z.string().min(1),
      id: z.string().min(1),
      href: z.string().nullable().optional(),
      label: z.string().nullable().optional()
    })
  ).optional()
});
const metadata = {
  GET: { requireAuth: true, requireFeatures: ["attachments.view"] },
  PATCH: { requireAuth: true, requireFeatures: ["attachments.manage"] },
  DELETE: { requireAuth: true, requireFeatures: ["attachments.manage"] }
};
async function resolveAttachmentId(ctx) {
  const params = ctx?.params;
  try {
    const { id } = await params;
    if (typeof id === "string" && id.trim().length) {
      return id;
    }
    return null;
  } catch {
    return null;
  }
}
async function GET(req, ctx) {
  const auth = await getAuthFromRequest(req);
  if (!auth || !auth.tenantId || !auth.orgId && !auth.isSuperAdmin) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const attachmentId = await resolveAttachmentId(ctx);
  if (!attachmentId) {
    return NextResponse.json({ error: "Attachment id is required" }, { status: 400 });
  }
  const { resolve } = await createRequestContainer();
  const em = resolve("em");
  let queryEngine = null;
  try {
    queryEngine = resolve("queryEngine");
  } catch {
    queryEngine = null;
  }
  const findFilter = {
    id: attachmentId,
    tenantId: auth.tenantId
  };
  if (auth.orgId) {
    findFilter.organizationId = auth.orgId;
  }
  const record = await em.findOne(Attachment, findFilter);
  if (!record) {
    return NextResponse.json({ error: "Attachment not found" }, { status: 404 });
  }
  const metadata2 = readAttachmentMetadata(record.storageMetadata);
  const partition = record.partitionCode ? await em.findOne(AttachmentPartition, { code: record.partitionCode }) : null;
  const customFieldValues = await loadCustomFieldValues({
    em,
    entityId: E.attachments.attachment,
    recordIds: [record.id],
    tenantIdByRecord: { [record.id]: record.tenantId ?? auth.tenantId ?? null },
    organizationIdByRecord: { [record.id]: record.organizationId ?? auth.orgId ?? null },
    tenantFallbacks: [auth.tenantId ?? null].filter((value) => !!value)
  });
  const customFields = normalizeCustomFieldResponse(customFieldValues[record.id]);
  const assignments = metadata2.assignments ?? [];
  const enrichments = await resolveAssignmentEnrichments(assignments, {
    queryEngine,
    tenantId: auth.tenantId,
    organizationId: auth.orgId
  });
  const enrichedAssignments = applyAssignmentEnrichments(assignments, enrichments);
  return NextResponse.json({
    item: {
      id: record.id,
      fileName: record.fileName,
      fileSize: record.fileSize,
      mimeType: record.mimeType,
      partitionCode: record.partitionCode,
      partitionTitle: partition?.title ?? null,
      tags: metadata2.tags ?? [],
      assignments: enrichedAssignments,
      content: record.content && record.content.trim() ? record.content : null,
      customFields
    }
  });
}
async function PATCH(req, ctx) {
  const auth = await getAuthFromRequest(req);
  if (!auth || !auth.tenantId || !auth.orgId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const attachmentId = await resolveAttachmentId(ctx);
  if (!attachmentId) {
    return NextResponse.json({ error: "Attachment id is required" }, { status: 400 });
  }
  const rawBody = await req.json().catch(() => null);
  const { base, custom } = splitCustomFieldPayload(rawBody);
  const parsed = updateSchema.safeParse(base);
  if (!parsed.success) {
    return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
  }
  const { resolve } = await createRequestContainer();
  const em = resolve("em");
  let queryEngine = null;
  try {
    queryEngine = resolve("queryEngine");
  } catch {
    queryEngine = null;
  }
  const dataEngine = resolve("dataEngine");
  const patchFilter = {
    id: attachmentId,
    tenantId: auth.tenantId,
    organizationId: auth.orgId
  };
  const record = await em.findOne(Attachment, patchFilter);
  if (!record) {
    return NextResponse.json({ error: "Attachment not found" }, { status: 404 });
  }
  const patch = {};
  if (parsed.data.tags) patch.tags = normalizeAttachmentTags(parsed.data.tags);
  if (parsed.data.assignments) patch.assignments = normalizeAttachmentAssignments(parsed.data.assignments);
  record.storageMetadata = mergeAttachmentMetadata(record.storageMetadata, patch);
  try {
    await em.transactional(async (tx) => {
      await tx.flush();
      if (dataEngine && custom && Object.keys(custom).length) {
        await setCustomFieldsIfAny({
          dataEngine,
          entityId: E.attachments.attachment,
          recordId: record.id,
          tenantId: record.tenantId ?? auth.tenantId ?? null,
          organizationId: record.organizationId ?? auth.orgId ?? null,
          values: custom
        });
      }
    });
  } catch (error) {
    logger.error("Failed to persist custom attributes", { err: error });
    return NextResponse.json({ error: "Failed to save attachment attributes." }, { status: 500 });
  }
  if (dataEngine) {
    await emitCrudSideEffects({
      dataEngine,
      action: "updated",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId ?? auth.orgId ?? null,
        tenantId: record.tenantId ?? auth.tenantId ?? null
      },
      events: attachmentCrudEvents,
      indexer: attachmentCrudIndexer
    });
    await dataEngine.flushOrmEntityChanges();
  }
  const metadata2 = readAttachmentMetadata(record.storageMetadata);
  const assignments = metadata2.assignments ?? [];
  const enrichments = await resolveAssignmentEnrichments(assignments, {
    queryEngine,
    tenantId: auth.tenantId,
    organizationId: auth.orgId
  });
  const enrichedAssignments = applyAssignmentEnrichments(assignments, enrichments);
  return NextResponse.json({
    ok: true,
    item: {
      id: record.id,
      tags: metadata2.tags ?? [],
      assignments: enrichedAssignments,
      customFields: normalizeCustomFieldResponse(custom ?? null)
    }
  });
}
async function DELETE(req, ctx) {
  const auth = await getAuthFromRequest(req);
  if (!auth || !auth.tenantId || !auth.orgId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const attachmentId = await resolveAttachmentId(ctx);
  if (!attachmentId) {
    return NextResponse.json({ error: "Attachment id is required" }, { status: 400 });
  }
  const { resolve } = await createRequestContainer();
  const em = resolve("em");
  const dataEngine = resolve("dataEngine");
  const storageDriverFactory = resolve("storageDriverFactory");
  const deleteFilter = {
    id: attachmentId,
    tenantId: auth.tenantId,
    organizationId: auth.orgId
  };
  const record = await em.findOne(Attachment, deleteFilter);
  if (!record) {
    return NextResponse.json({ error: "Attachment not found" }, { status: 404 });
  }
  const deleteDriver = await storageDriverFactory.resolveForPartition(record.partitionCode, {
    tenantId: record.tenantId ?? auth.tenantId,
    organizationId: record.organizationId ?? auth.orgId
  });
  const recordPartitionCode = record.partitionCode;
  const recordStoragePath = record.storagePath;
  await em.remove(record).flush();
  await deleteDriver.delete(recordPartitionCode, recordStoragePath);
  if (dataEngine) {
    await emitCrudSideEffects({
      dataEngine,
      action: "deleted",
      entity: record,
      identifiers: {
        id: record.id,
        organizationId: record.organizationId ?? auth.orgId ?? null,
        tenantId: record.tenantId ?? auth.tenantId ?? null
      },
      events: attachmentCrudEvents,
      indexer: attachmentCrudIndexer
    });
    await dataEngine.flushOrmEntityChanges();
  }
  return NextResponse.json({ ok: true });
}
const openApi = {
  tag: attachmentsTag,
  summary: "Attachment detail management",
  methods: {
    GET: {
      summary: "Get attachment details",
      description: "Returns complete details of an attachment including metadata, tags, assignments, and custom fields.",
      responses: [
        { status: 200, description: "Attachment details", schema: attachmentDetailResponseSchema }
      ],
      errors: [
        { status: 400, description: "Invalid attachment ID", schema: attachmentErrorSchema },
        { status: 401, description: "Unauthorized", schema: attachmentErrorSchema },
        { status: 404, description: "Attachment not found", schema: attachmentErrorSchema }
      ]
    },
    PATCH: {
      summary: "Update attachment metadata",
      description: "Updates attachment tags, assignments, and custom fields. Emits CRUD side effects for indexing and events.",
      requestBody: {
        contentType: "application/json",
        schema: updateSchema
      },
      responses: [
        { status: 200, description: "Attachment updated successfully", schema: z.object({ ok: z.literal(true), item: z.any() }) }
      ],
      errors: [
        { status: 400, description: "Invalid payload or attachment ID", schema: attachmentErrorSchema },
        { status: 401, description: "Unauthorized", schema: attachmentErrorSchema },
        { status: 404, description: "Attachment not found", schema: attachmentErrorSchema },
        { status: 500, description: "Failed to save attributes", schema: attachmentErrorSchema }
      ]
    },
    DELETE: {
      summary: "Delete attachment",
      description: "Permanently deletes an attachment file from storage and database. Emits CRUD side effects.",
      responses: [
        { status: 200, description: "Attachment deleted successfully", schema: z.object({ ok: z.literal(true) }) }
      ],
      errors: [
        { status: 400, description: "Invalid attachment ID", schema: attachmentErrorSchema },
        { status: 401, description: "Unauthorized", schema: attachmentErrorSchema },
        { status: 404, description: "Attachment not found", schema: attachmentErrorSchema }
      ]
    }
  }
};
export {
  DELETE,
  GET,
  PATCH,
  metadata,
  openApi
};
//# sourceMappingURL=route.js.map
