import { z } from "zod";
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
import { splitCustomFieldPayload } from "@open-mercato/shared/lib/crud/custom-fields";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { SalesChannel } from "../../data/entities.js";
import { channelCreateSchema, channelUpdateSchema } from "../../data/validators.js";
import { buildAggregateSearchFilter, parseScopedCommandInput, resolveCrudRecordId } from "../utils.js";
import { E } from "../../../../generated/entities.ids.generated.js";
import * as F from "../../../../generated/entities/sales_channel/index.js";
import {
  createPagedListResponseSchema,
  createSalesCrudOpenApi,
  defaultDeleteRequestSchema
} from "../openapi.js";
import { CatalogOffer } from "@open-mercato/core/modules/catalog/data/entities";
import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("sales");
const rawBodySchema = z.object({}).passthrough();
const UUID_REGEX = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
const listSchema = z.object({
  page: z.coerce.number().min(1).default(1),
  pageSize: z.coerce.number().min(1).max(100).default(50),
  search: z.string().optional(),
  id: z.string().uuid().optional(),
  ids: z.string().optional(),
  isActive: z.string().optional(),
  sortField: z.string().optional(),
  sortDir: z.enum(["asc", "desc"]).optional(),
  withDeleted: z.coerce.boolean().optional()
}).passthrough();
const routeMetadata = {
  GET: { requireAuth: true, requireFeatures: ["sales.channels.manage"] },
  POST: { requireAuth: true, requireFeatures: ["sales.channels.manage"] },
  PUT: { requireAuth: true, requireFeatures: ["sales.channels.manage"] },
  DELETE: { requireAuth: true, requireFeatures: ["sales.channels.manage"] }
};
const metadata = routeMetadata;
const salesChannelItemSchema = z.object({
  id: z.string().uuid(),
  name: z.string(),
  code: z.string().nullable(),
  description: z.string().nullable(),
  statusEntryId: z.string().uuid().nullable(),
  isActive: z.boolean(),
  organizationId: z.string().uuid().nullable(),
  tenantId: z.string().uuid().nullable(),
  createdAt: z.string(),
  updatedAt: z.string(),
  customFields: z.record(z.string(), z.unknown()).optional(),
  offerCount: z.number().optional()
});
const salesChannelListResponseSchema = createPagedListResponseSchema(salesChannelItemSchema);
function parseIdList(raw) {
  if (!raw) return [];
  return raw.split(",").map((value) => value.trim()).filter((value) => UUID_REGEX.test(value));
}
function buildSearchFilters(query) {
  const filters = {};
  if (query.id) filters.id = { $eq: query.id };
  else {
    const ids = parseIdList(query.ids);
    if (ids.length) filters.id = { $in: ids };
  }
  const searchFilter = buildAggregateSearchFilter(query.search);
  if (searchFilter) Object.assign(filters, searchFilter);
  const isActive = parseBooleanToken(query.isActive);
  if (isActive !== null) filters.is_active = isActive;
  return filters;
}
const crud = makeCrudRoute({
  metadata: routeMetadata,
  orm: {
    entity: SalesChannel,
    idField: "id",
    orgField: "organizationId",
    tenantField: "tenantId",
    softDeleteField: "deletedAt"
  },
  indexer: { entityType: E.sales.sales_channel },
  list: {
    schema: listSchema,
    entityId: E.sales.sales_channel,
    fields: [
      F.id,
      F.name,
      F.code,
      F.description,
      F.status_entry_id,
      F.is_active,
      F.website_url,
      F.contact_email,
      F.contact_phone,
      F.address_line1,
      F.address_line2,
      F.city,
      F.region,
      F.postal_code,
      F.country,
      F.latitude,
      F.longitude,
      F.organization_id,
      F.tenant_id,
      F.created_at,
      F.updated_at
    ],
    sortFieldMap: {
      id: F.id,
      name: F.name,
      code: F.code,
      createdAt: F.created_at,
      updatedAt: F.updated_at
    },
    buildFilters: async (query) => buildSearchFilters(query),
    decorateCustomFields: { entityIds: [E.sales.sales_channel] },
    transformItem: (item) => {
      const offerCount = typeof item.offerCount === "number" ? item.offerCount : typeof item.offer_count === "number" ? item.offer_count : 0;
      const base = {
        id: item.id,
        name: item.name,
        code: item.code ?? null,
        description: item.description ?? null,
        statusEntryId: item.status_entry_id ?? null,
        isActive: item.is_active ?? false,
        websiteUrl: item.website_url ?? null,
        contactEmail: item.contact_email ?? null,
        contactPhone: item.contact_phone ?? null,
        addressLine1: item.address_line1 ?? null,
        addressLine2: item.address_line2 ?? null,
        city: item.city ?? null,
        region: item.region ?? null,
        postalCode: item.postal_code ?? null,
        country: item.country ?? null,
        latitude: item.latitude ?? null,
        longitude: item.longitude ?? null,
        organizationId: item.organization_id ?? null,
        tenantId: item.tenant_id ?? null,
        createdAt: item.created_at,
        updatedAt: item.updated_at,
        offerCount
      };
      const { custom } = splitCustomFieldPayload(item);
      return Object.keys(custom).length ? { ...base, customFields: custom } : base;
    }
  },
  actions: {
    create: {
      commandId: "sales.channels.create",
      schema: rawBodySchema,
      mapInput: async ({ raw, ctx }) => {
        const { translate } = await resolveTranslations();
        return parseScopedCommandInput(channelCreateSchema, raw ?? {}, ctx, translate);
      },
      response: ({ result }) => ({ id: result?.channelId ?? result?.id ?? null }),
      status: 201
    },
    update: {
      commandId: "sales.channels.update",
      schema: rawBodySchema,
      mapInput: async ({ raw, ctx }) => {
        const { translate } = await resolveTranslations();
        return parseScopedCommandInput(channelUpdateSchema, raw ?? {}, ctx, translate);
      },
      response: () => ({ ok: true })
    },
    delete: {
      commandId: "sales.channels.delete",
      schema: rawBodySchema,
      mapInput: async ({ parsed, ctx }) => {
        const { translate } = await resolveTranslations();
        const id = resolveCrudRecordId(parsed, ctx, translate);
        return { id };
      },
      response: () => ({ ok: true })
    }
  },
  hooks: {
    afterList: async (payload, ctx) => {
      await decorateChannelsWithOfferCounts(payload, ctx);
    }
  }
});
const openApi = createSalesCrudOpenApi({
  resourceName: "Sales channel",
  pluralName: "Sales channels",
  description: "Manage sales channels to segment orders and pricing across marketplaces or stores.",
  querySchema: listSchema,
  listResponseSchema: salesChannelListResponseSchema,
  create: { schema: channelCreateSchema },
  update: { schema: channelUpdateSchema },
  del: { schema: defaultDeleteRequestSchema }
});
const GET = crud.GET;
const POST = crud.POST;
const PUT = crud.PUT;
const DELETE = crud.DELETE;
async function decorateChannelsWithOfferCounts(payload, ctx) {
  const items = Array.isArray(payload.items) ? payload.items : [];
  if (!items.length) return;
  const channelIds = items.map((item) => {
    const value = item?.id;
    return typeof value === "string" && value.length ? value : null;
  }).filter((value) => !!value);
  if (!channelIds.length) return;
  try {
    const em = ctx.container.resolve("em");
    const offers = await em.find(
      CatalogOffer,
      { channelId: { $in: channelIds }, deletedAt: null },
      { fields: ["id", "channelId"] }
    );
    const countMap = /* @__PURE__ */ new Map();
    offers.forEach((offer) => {
      const channelId = offer.channelId;
      if (!channelId) return;
      countMap.set(channelId, (countMap.get(channelId) ?? 0) + 1);
    });
    items.forEach((item) => {
      const id = typeof item.id === "string" ? item.id : null;
      if (!id) return;
      item.offerCount = countMap.get(id) ?? 0;
    });
  } catch (err) {
    logger.warn("sales.channels failed to resolve channel offer counts", { err });
  }
}
export {
  DELETE,
  GET,
  POST,
  PUT,
  buildSearchFilters,
  decorateChannelsWithOfferCounts,
  metadata,
  openApi,
  parseIdList
};
//# sourceMappingURL=route.js.map
