import { z } from "zod";
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { Dictionary, DictionaryEntry } from "@open-mercato/core/modules/dictionaries/data/entities";
import { statusDictionaryCreateSchema, statusDictionaryUpdateSchema } from "../data/validators.js";
import { getSalesDictionaryDefinition, ensureSalesDictionary } from "./dictionaries.js";
import { buildAggregateSearchFilter, parseScopedCommandInput, resolveCrudRecordId } from "../api/utils.js";
import {
  createPagedListResponseSchema,
  createSalesCrudOpenApi,
  defaultDeleteRequestSchema
} from "../api/openapi.js";
async function resolveSalesDictionaryForCandidates(input) {
  const { em, tenantId, kind, dictionaryKey, candidateOrgIds } = input;
  if (candidateOrgIds.length === 0) return null;
  const matches = await em.find(Dictionary, {
    tenantId,
    key: dictionaryKey,
    organizationId: { $in: candidateOrgIds },
    deletedAt: null
  });
  if (matches.length > 0) {
    const byOrg = /* @__PURE__ */ new Map();
    for (const dict of matches) {
      if (dict.organizationId && !byOrg.has(dict.organizationId)) {
        byOrg.set(dict.organizationId, dict);
      }
    }
    for (const orgId of candidateOrgIds) {
      const dictionary2 = byOrg.get(orgId);
      if (dictionary2) {
        return { dictionaryId: dictionary2.id, organizationId: orgId };
      }
    }
  }
  const firstOrgId = candidateOrgIds[0];
  const dictionary = await ensureSalesDictionary({
    em,
    tenantId,
    organizationId: firstOrgId,
    kind
  });
  if (dictionary) {
    return { dictionaryId: dictionary.id, organizationId: firstOrgId };
  }
  return null;
}
function makeStatusDictionaryRoute(config) {
  const { kind, entityId, fieldConstants: F } = config;
  const definition = getSalesDictionaryDefinition(kind);
  const rawBodySchema = z.object({}).passthrough();
  const listSchema = z.object({
    page: z.coerce.number().min(1).default(1),
    pageSize: z.coerce.number().min(1).max(100).default(50),
    id: z.string().uuid().optional(),
    search: z.string().optional(),
    sortField: z.string().optional(),
    sortDir: z.enum(["asc", "desc"]).optional()
  }).passthrough();
  const metadata = {
    GET: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
    POST: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
    PUT: { requireAuth: true, requireFeatures: ["sales.settings.manage"] },
    DELETE: { requireAuth: true, requireFeatures: ["sales.settings.manage"] }
  };
  const dictionaryItemSchema = z.object({
    id: z.string().uuid(),
    value: z.string(),
    label: z.string().nullable(),
    color: z.string().nullable(),
    icon: z.string().nullable(),
    organizationId: z.string().uuid().nullable(),
    tenantId: z.string().uuid().nullable(),
    createdAt: z.string(),
    updatedAt: z.string()
  });
  const dictionaryListResponseSchema = createPagedListResponseSchema(dictionaryItemSchema);
  const normalizeId = (value) => {
    if (typeof value !== "string") return null;
    const trimmed = value.trim();
    return trimmed.length > 0 ? trimmed : null;
  };
  async function resolveDictionaryContext(ctx) {
    if (!ctx.auth || !ctx.auth.tenantId) {
      throw new CrudHttpError(401, { error: "Tenant context is required." });
    }
    const em = ctx.container.resolve("em");
    const tenantId = ctx.auth.tenantId;
    const candidateOrgIds = /* @__PURE__ */ new Set();
    const pushCandidate = (value) => {
      const normalized = normalizeId(value);
      if (normalized) candidateOrgIds.add(normalized);
    };
    pushCandidate(ctx.selectedOrganizationId);
    pushCandidate(ctx.auth.orgId ?? null);
    const scope = ctx.organizationScope;
    if (scope) {
      if (Array.isArray(scope.filterIds)) {
        for (const id of scope.filterIds) pushCandidate(id);
      }
      if (Array.isArray(scope.allowedIds)) {
        for (const id of scope.allowedIds) pushCandidate(id);
      }
    }
    const orderedOrgIds = Array.from(candidateOrgIds);
    const resolved = await resolveSalesDictionaryForCandidates({
      em,
      tenantId,
      kind,
      dictionaryKey: definition.key,
      candidateOrgIds: orderedOrgIds
    });
    if (resolved) return resolved;
    const fallback = await em.findOne(
      Dictionary,
      {
        tenantId,
        key: definition.key,
        deletedAt: null
      },
      { orderBy: { createdAt: "asc" } }
    );
    if (fallback) {
      return { dictionaryId: fallback.id, organizationId: fallback.organizationId };
    }
    throw new CrudHttpError(400, { error: "Organization context is required." });
  }
  const crud = makeCrudRoute({
    metadata,
    orm: {
      entity: DictionaryEntry,
      idField: "id",
      orgField: "organizationId",
      tenantField: "tenantId",
      softDeleteField: null
    },
    list: {
      schema: listSchema,
      entityId,
      fields: [
        F.id,
        F.value,
        F.label,
        F.color,
        F.icon,
        F.organization_id,
        F.tenant_id,
        F.created_at,
        F.updated_at
      ],
      sortFieldMap: {
        id: F.id,
        value: F.value,
        label: F.label,
        createdAt: F.created_at,
        updatedAt: F.updated_at
      },
      buildFilters: async (query, ctx) => {
        const { dictionaryId } = await resolveDictionaryContext(ctx);
        const filters = {
          dictionary_id: dictionaryId
        };
        if (query.id) filters.id = { $eq: query.id };
        const searchFilter = buildAggregateSearchFilter(query.search);
        if (searchFilter) Object.assign(filters, searchFilter);
        return filters;
      },
      transformItem: (item) => ({
        id: item.id,
        value: item.value,
        label: item.label,
        color: item.color ?? null,
        icon: item.icon ?? null,
        organizationId: item.organization_id ?? null,
        tenantId: item.tenant_id ?? null,
        createdAt: item.created_at,
        updatedAt: item.updated_at
      })
    },
    actions: {
      create: {
        commandId: `${definition.commandPrefix}.create`,
        schema: rawBodySchema,
        mapInput: async ({ raw, ctx }) => {
          const { translate } = await resolveTranslations();
          return parseScopedCommandInput(statusDictionaryCreateSchema, raw ?? {}, ctx, translate);
        },
        response: ({ result }) => ({ id: result?.entryId ?? null }),
        status: 201
      },
      update: {
        commandId: `${definition.commandPrefix}.update`,
        schema: rawBodySchema,
        mapInput: async ({ raw, ctx }) => {
          const { translate } = await resolveTranslations();
          return parseScopedCommandInput(statusDictionaryUpdateSchema, raw ?? {}, ctx, translate);
        },
        response: () => ({ ok: true })
      },
      delete: {
        commandId: `${definition.commandPrefix}.delete`,
        schema: rawBodySchema,
        mapInput: async ({ parsed, ctx }) => {
          const { translate } = await resolveTranslations();
          const id = resolveCrudRecordId(parsed, ctx, translate);
          return { id };
        },
        response: () => ({ ok: true })
      }
    }
  });
  const openApi = createSalesCrudOpenApi({
    resourceName: config.openApi.resourceName,
    pluralName: config.openApi.pluralName,
    description: config.openApi.description,
    querySchema: listSchema,
    listResponseSchema: dictionaryListResponseSchema,
    create: { schema: statusDictionaryCreateSchema },
    update: { schema: statusDictionaryUpdateSchema },
    del: { schema: defaultDeleteRequestSchema }
  });
  return {
    metadata,
    openApi,
    GET: crud.GET,
    POST: crud.POST,
    PUT: crud.PUT,
    DELETE: crud.DELETE
  };
}
export {
  makeStatusDictionaryRoute,
  resolveSalesDictionaryForCandidates
};
//# sourceMappingURL=makeStatusDictionaryRoute.js.map
