import { z } from "zod";
import { defineApiBackedAiTool } from "@open-mercato/ai-assistant/modules/ai_assistant/lib/api-backed-tool";
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { CatalogProductPrice } from "../data/entities.js";
import { assertTenantScope } from "./types.js";
import { listPriceKindsCore } from "./_shared.js";
function resolveEm(ctx) {
  return ctx.container.resolve("em");
}
function buildScope(ctx, tenantId) {
  return { tenantId, organizationId: ctx.organizationId };
}
const listPricesInput = z.object({
  productId: z.string().uuid().optional().describe("Restrict to prices attached to this product."),
  variantId: z.string().uuid().optional().describe("Restrict to prices attached to this variant."),
  priceKindId: z.string().uuid().optional().describe("Restrict to this price kind."),
  limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
  offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
}).passthrough();
const listPricesTool = defineApiBackedAiTool({
  name: "catalog.list_prices",
  displayName: "List prices",
  description: "List catalog prices (base + offer-scoped) for the caller tenant + organization. Filters: product, variant, or price kind.",
  inputSchema: listPricesInput,
  requiredFeatures: ["catalog.products.view"],
  toOperation: (input, ctx) => {
    assertTenantScope(ctx);
    const limit = input.limit ?? 50;
    const offset = input.offset ?? 0;
    const page = Math.floor(offset / limit) + 1;
    const query = {
      page,
      pageSize: limit
    };
    if (input.productId) query.productId = input.productId;
    if (input.variantId) query.variantId = input.variantId;
    if (input.priceKindId) query.priceKindId = input.priceKindId;
    const operation = {
      method: "GET",
      path: "/catalog/prices",
      query
    };
    return operation;
  },
  mapResponse: (response, input) => {
    const limit = input.limit ?? 50;
    const offset = input.offset ?? 0;
    const data = response.data ?? {};
    const rawItems = Array.isArray(data.items) ? data.items : [];
    return {
      items: rawItems.map((row) => {
        const startsAtRaw = row.starts_at ?? row.startsAt ?? null;
        const startsAt = startsAtRaw ? new Date(String(startsAtRaw)).toISOString() : null;
        const endsAtRaw = row.ends_at ?? row.endsAt ?? null;
        const endsAt = endsAtRaw ? new Date(String(endsAtRaw)).toISOString() : null;
        const createdAtRaw = row.created_at ?? row.createdAt ?? null;
        const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
        return {
          id: row.id,
          priceKindId: row.price_kind_id ?? row.priceKindId ?? null,
          productId: row.product_id ?? row.productId ?? null,
          variantId: row.variant_id ?? row.variantId ?? null,
          offerId: row.offer_id ?? row.offerId ?? null,
          currencyCode: row.currency_code ?? row.currencyCode ?? null,
          kind: row.kind ?? null,
          minQuantity: row.min_quantity ?? row.minQuantity ?? null,
          maxQuantity: row.max_quantity ?? row.maxQuantity ?? null,
          unitPriceNet: row.unit_price_net ?? row.unitPriceNet ?? null,
          unitPriceGross: row.unit_price_gross ?? row.unitPriceGross ?? null,
          taxRate: row.tax_rate ?? row.taxRate ?? null,
          taxAmount: row.tax_amount ?? row.taxAmount ?? null,
          channelId: row.channel_id ?? row.channelId ?? null,
          userId: row.user_id ?? row.userId ?? null,
          userGroupId: row.user_group_id ?? row.userGroupId ?? null,
          customerId: row.customer_id ?? row.customerId ?? null,
          customerGroupId: row.customer_group_id ?? row.customerGroupId ?? null,
          startsAt,
          endsAt,
          organizationId: row.organization_id ?? row.organizationId ?? null,
          tenantId: row.tenant_id ?? row.tenantId ?? null,
          createdAt
        };
      }),
      total: typeof data.total === "number" ? data.total : 0,
      limit,
      offset
    };
  }
});
const listPriceKindsInput = z.object({
  limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
  offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
}).passthrough();
const listPriceKindsTool = {
  name: "catalog.list_price_kinds_base",
  displayName: "List price kinds (base)",
  description: "Enumerate the tenant price kinds. Base coverage tool \u2014 Step 3.11 (D18) owns `catalog.list_price_kinds` verbatim; this tool uses a distinct name to avoid collision.",
  inputSchema: listPriceKindsInput,
  requiredFeatures: ["catalog.settings.manage"],
  tags: ["read", "catalog"],
  handler: async (rawInput, ctx) => {
    const { tenantId } = assertTenantScope(ctx);
    const input = listPriceKindsInput.parse(rawInput);
    return listPriceKindsCore(ctx, input, tenantId);
  }
};
const listOffersInput = z.object({
  productId: z.string().uuid().optional().describe("Restrict to offers for this product."),
  variantId: z.string().uuid().optional().describe("Restrict to offers whose prices are variant-scoped."),
  active: z.boolean().optional().describe("When true, only active (non-archived) offers are returned."),
  limit: z.number().int().min(1).max(100).optional().describe("Max rows (default 50, max 100)."),
  offset: z.number().int().min(0).optional().describe("Rows to skip (default 0).")
}).passthrough();
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
async function resolveOfferIdsForVariant(ctx, tenantId, variantId) {
  const em = resolveEm(ctx);
  const priceWhere = { tenantId, variant: variantId };
  if (ctx.organizationId) priceWhere.organizationId = ctx.organizationId;
  const prices = await findWithDecryption(
    em,
    CatalogProductPrice,
    priceWhere,
    void 0,
    buildScope(ctx, tenantId)
  );
  const offerIds = prices.map((price) => price.offer).map((offer) => offer && typeof offer === "object" ? offer.id : offer).filter((value) => typeof value === "string" && value.length > 0);
  return Array.from(new Set(offerIds));
}
const listOffersTool = defineApiBackedAiTool({
  name: "catalog.list_offers",
  displayName: "List offers",
  description: "List catalog offers for the caller tenant + organization, optionally narrowed to a product (or a variant via its prices).",
  inputSchema: listOffersInput,
  // Must cover the underlying route. `GET /catalog/offers` requires
  // `sales.channels.manage` (offers are sales-channel scoped); the API-backed
  // runner fails closed when the tool's features don't cover the route's.
  // `catalog.products.view` stays for the variant→offer resolution path.
  requiredFeatures: ["catalog.products.view", "sales.channels.manage"],
  toOperation: async (input, ctx) => {
    const { tenantId } = assertTenantScope(ctx);
    const limit = input.limit ?? 50;
    const offset = input.offset ?? 0;
    const page = Math.floor(offset / limit) + 1;
    const query = {
      page,
      pageSize: limit
    };
    if (input.productId) query.productId = input.productId;
    if (input.active === true) query.isActive = "true";
    if (input.variantId) {
      const offerIds = await resolveOfferIdsForVariant(ctx, tenantId, input.variantId);
      if (offerIds.length === 0) {
        query.id = NIL_UUID;
      } else if (offerIds.length === 1) {
        query.id = offerIds[0];
      }
    }
    const operation = {
      method: "GET",
      path: "/catalog/offers",
      query
    };
    return operation;
  },
  mapResponse: async (response, input, ctx) => {
    const limit = input.limit ?? 50;
    const offset = input.offset ?? 0;
    const data = response.data ?? {};
    let rawItems = Array.isArray(data.items) ? data.items : [];
    let total = typeof data.total === "number" ? data.total : 0;
    if (input.variantId) {
      const { tenantId } = assertTenantScope(ctx);
      const offerIds = await resolveOfferIdsForVariant(ctx, tenantId, input.variantId);
      const offerIdSet = new Set(offerIds);
      rawItems = rawItems.filter((row) => typeof row.id === "string" && offerIdSet.has(row.id));
      total = rawItems.length;
    }
    return {
      items: rawItems.map((row) => {
        const createdAtRaw = row.created_at ?? row.createdAt ?? null;
        const createdAt = createdAtRaw ? new Date(String(createdAtRaw)).toISOString() : null;
        return {
          id: row.id,
          title: row.title ?? "",
          description: row.description ?? null,
          channelId: row.channel_id ?? row.channelId ?? null,
          productId: row.product_id ?? row.productId ?? null,
          defaultMediaId: row.default_media_id ?? row.defaultMediaId ?? null,
          defaultMediaUrl: row.default_media_url ?? row.defaultMediaUrl ?? null,
          isActive: !!(row.is_active ?? row.isActive),
          organizationId: row.organization_id ?? row.organizationId ?? null,
          tenantId: row.tenant_id ?? row.tenantId ?? null,
          createdAt
        };
      }),
      total,
      limit,
      offset
    };
  }
});
const pricesOffersAiTools = [
  listPricesTool,
  listPriceKindsTool,
  listOffersTool
];
var prices_offers_pack_default = pricesOffersAiTools;
export {
  prices_offers_pack_default as default,
  pricesOffersAiTools
};
//# sourceMappingURL=prices-offers-pack.js.map
