import { NextResponse } from "next/server";
import { z } from "zod";
import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import {
  runCrudMutationGuardAfterSuccess,
  validateCrudMutationGuard
} from "@open-mercato/shared/lib/crud/mutation-guard";
import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { resolveAuthActorId } from "@open-mercato/core/modules/customers/lib/interactionRequestContext";
import { CustomerPersonCompanyLink } from "@open-mercato/core/modules/customers/data/entities";
import {
  personCompanyLinkDeleteSchema,
  personCompanyLinkUpdateSchema
} from "@open-mercato/core/modules/customers/data/validators";
import { loadPersonContext } from "../context.js";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
const paramsSchema = z.object({
  id: z.string().uuid(),
  linkId: z.string().uuid()
});
async function resolveLinkId(em, rawLinkId, personEntityId, tenantId, organizationId) {
  const decryptionScope = { tenantId, organizationId };
  const directFilter = organizationId ? { id: rawLinkId, tenantId, organizationId, deletedAt: null } : { id: rawLinkId, tenantId, deletedAt: null };
  const direct = await findOneWithDecryption(
    em,
    CustomerPersonCompanyLink,
    directFilter,
    void 0,
    decryptionScope
  );
  if (direct) return direct.id;
  const companyFilter = organizationId ? {
    person: personEntityId,
    company: rawLinkId,
    tenantId,
    organizationId,
    deletedAt: null
  } : { person: personEntityId, company: rawLinkId, tenantId, deletedAt: null };
  const viaCompany = await findOneWithDecryption(
    em,
    CustomerPersonCompanyLink,
    companyFilter,
    void 0,
    decryptionScope
  );
  return viaCompany?.id ?? null;
}
const updateSchema = z.object({
  isPrimary: z.boolean().optional()
});
const updateResponseSchema = z.object({
  ok: z.literal(true),
  result: z.object({
    id: z.string().uuid(),
    companyId: z.string().uuid(),
    displayName: z.string(),
    isPrimary: z.boolean()
  }).nullable()
});
const metadata = {
  PATCH: { requireAuth: true, requireFeatures: ["customers.people.manage"] },
  DELETE: { requireAuth: true, requireFeatures: ["customers.people.manage"] }
};
const openApi = {
  tag: "Customers",
  methods: {
    PATCH: {
      summary: "Update a linked company for a person",
      requestBody: { schema: updateSchema },
      responses: [{ status: 200, description: "Updated company link", schema: updateResponseSchema }]
    },
    DELETE: {
      summary: "Remove a linked company from a person",
      responses: [{ status: 200, description: "Deletion result", schema: z.object({ ok: z.literal(true) }) }]
    }
  }
};
async function PATCH(req, ctx) {
  const { translate } = await resolveTranslations();
  try {
    const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId });
    const payload = updateSchema.parse(await readJsonSafe(req, {}));
    const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id);
    if (!selectedOrganizationId) {
      throw new CrudHttpError(400, { error: translate("customers.errors.organization_required", "Organization context is required") });
    }
    const guardUserId = resolveAuthActorId(auth);
    const guardResult = await validateCrudMutationGuard(container, {
      tenantId: auth.tenantId,
      organizationId: selectedOrganizationId,
      userId: guardUserId,
      resourceKind: "customers.person",
      resourceId: person.id,
      operation: "custom",
      requestMethod: req.method,
      requestHeaders: req.headers,
      mutationPayload: payload
    });
    if (guardResult && !guardResult.ok) {
      return NextResponse.json(guardResult.body, { status: guardResult.status });
    }
    if (payload.isPrimary === void 0) {
      return NextResponse.json({ ok: true, result: null });
    }
    const resolveEm = container.resolve("em").fork();
    const resolvedLinkId = await resolveLinkId(
      resolveEm,
      linkId,
      person.id,
      auth.tenantId,
      selectedOrganizationId
    );
    if (!resolvedLinkId) {
      throw new CrudHttpError(404, {
        error: translate("customers.errors.person_company_link_not_found", "Person-company link not found")
      });
    }
    const commandInput = personCompanyLinkUpdateSchema.parse({
      linkId: resolvedLinkId,
      isPrimary: payload.isPrimary,
      tenantId: auth.tenantId,
      organizationId: selectedOrganizationId
    });
    const commandBus = container.resolve("commandBus");
    const { result, logEntry } = await commandBus.execute(
      "customers.personCompanyLinks.update",
      {
        input: commandInput,
        ctx: {
          container,
          auth,
          organizationScope: null,
          selectedOrganizationId,
          organizationIds: [selectedOrganizationId],
          request: req
        }
      }
    );
    if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
      await runCrudMutationGuardAfterSuccess(container, {
        tenantId: auth.tenantId,
        organizationId: selectedOrganizationId,
        userId: guardUserId,
        resourceKind: "customers.person",
        resourceId: person.id,
        operation: "custom",
        requestMethod: req.method,
        requestHeaders: req.headers,
        metadata: guardResult.metadata ?? null
      });
    }
    const freshEm = container.resolve("em").fork();
    const linkRecord = await findOneWithDecryption(
      freshEm,
      CustomerPersonCompanyLink,
      { id: result.linkId, tenantId: auth.tenantId, organizationId: selectedOrganizationId },
      { populate: ["company"] },
      { tenantId: auth.tenantId, organizationId: selectedOrganizationId }
    );
    const company = linkRecord && typeof linkRecord.company !== "string" ? linkRecord.company : null;
    const response = NextResponse.json({
      ok: true,
      result: linkRecord ? {
        id: linkRecord.id,
        companyId: company?.id ?? "",
        displayName: company?.displayName ?? "",
        isPrimary: Boolean(linkRecord.isPrimary)
      } : null
    });
    if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {
      response.headers.set(
        "x-om-operation",
        serializeOperationMetadata({
          id: logEntry.id,
          undoToken: logEntry.undoToken,
          commandId: logEntry.commandId,
          actionLabel: logEntry.actionLabel ?? null,
          resourceKind: logEntry.resourceKind ?? "customers.personCompanyLink",
          resourceId: logEntry.resourceId ?? result.linkId,
          executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
        })
      );
    }
    return response;
  } catch (err) {
    if (isCrudHttpError(err)) {
      return NextResponse.json(err.body, { status: err.status });
    }
    return NextResponse.json({ error: translate("customers.errors.internal", "Internal server error") }, { status: 500 });
  }
}
async function DELETE(req, ctx) {
  const { translate } = await resolveTranslations();
  try {
    const { id, linkId } = paramsSchema.parse({ id: ctx.params?.id, linkId: ctx.params?.linkId });
    const { container, auth, selectedOrganizationId, person } = await loadPersonContext(req, id);
    if (!selectedOrganizationId) {
      throw new CrudHttpError(400, { error: translate("customers.errors.organization_required", "Organization context is required") });
    }
    const guardUserId = resolveAuthActorId(auth);
    const guardResult = await validateCrudMutationGuard(container, {
      tenantId: auth.tenantId,
      organizationId: selectedOrganizationId,
      userId: guardUserId,
      resourceKind: "customers.person",
      resourceId: person.id,
      operation: "custom",
      requestMethod: req.method,
      requestHeaders: req.headers,
      mutationPayload: { id: linkId }
    });
    if (guardResult && !guardResult.ok) {
      return NextResponse.json(guardResult.body, { status: guardResult.status });
    }
    const resolveEm = container.resolve("em").fork();
    const resolvedLinkId = await resolveLinkId(
      resolveEm,
      linkId,
      person.id,
      auth.tenantId,
      selectedOrganizationId
    );
    if (!resolvedLinkId) {
      throw new CrudHttpError(404, {
        error: translate("customers.errors.person_company_link_not_found", "Person-company link not found")
      });
    }
    const commandInput = personCompanyLinkDeleteSchema.parse({
      linkId: resolvedLinkId,
      tenantId: auth.tenantId,
      organizationId: selectedOrganizationId
    });
    const commandBus = container.resolve("commandBus");
    const { result, logEntry } = await commandBus.execute(
      "customers.personCompanyLinks.delete",
      {
        input: commandInput,
        ctx: {
          container,
          auth,
          organizationScope: null,
          selectedOrganizationId,
          organizationIds: [selectedOrganizationId],
          request: req
        }
      }
    );
    if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
      await runCrudMutationGuardAfterSuccess(container, {
        tenantId: auth.tenantId,
        organizationId: selectedOrganizationId,
        userId: guardUserId,
        resourceKind: "customers.person",
        resourceId: person.id,
        operation: "custom",
        requestMethod: req.method,
        requestHeaders: req.headers,
        metadata: guardResult.metadata ?? null
      });
    }
    const response = NextResponse.json({ ok: true });
    if (logEntry?.undoToken && logEntry.id && logEntry.commandId) {
      response.headers.set(
        "x-om-operation",
        serializeOperationMetadata({
          id: logEntry.id,
          undoToken: logEntry.undoToken,
          commandId: logEntry.commandId,
          actionLabel: logEntry.actionLabel ?? null,
          resourceKind: logEntry.resourceKind ?? "customers.personCompanyLink",
          resourceId: logEntry.resourceId ?? result.linkId,
          executedAt: logEntry.createdAt instanceof Date ? logEntry.createdAt.toISOString() : (/* @__PURE__ */ new Date()).toISOString()
        })
      );
    }
    return response;
  } catch (err) {
    if (isCrudHttpError(err)) {
      return NextResponse.json(err.body, { status: err.status });
    }
    return NextResponse.json({ error: translate("customers.errors.internal", "Internal server error") }, { status: 500 });
  }
}
export {
  DELETE,
  PATCH,
  metadata,
  openApi
};
//# sourceMappingURL=route.js.map
