import * as z from "zod";

// ─── Wash Package Schema (admin) ─────────────────────────────────────────────

/** Digits-only, finite, >= 0 — the shared shape of every price field here */
function isNonNegativeAmount(value: string): boolean {
  const parsed = Number(value);
  return Number.isFinite(parsed) && parsed >= 0;
}

/**
 * Admin catalog package form.
 *
 * Numeric fields are kept as strings (the controls are text inputs — see
 * `CurrencyInput`'s value contract) and coerced on submit. Bounds mirror the
 * backend DTOs exactly: `estimatedDuration` is `@IsInt() @Min(1)`, prices are
 * `@IsNumber() @Min(0)`, and the service layer rejects `maxPrice < minPrice`.
 * Messages are dictionary keys — resolved through `t()` by FormField.
 */
export const washPackageSchema = z
  .object({
    name: z
      .string()
      .trim()
      .min(1, { message: "catalog.validation.nameRequired" }),
    description: z.string(),
    estimatedDuration: z
      .string()
      .min(1, { message: "catalog.validation.durationRequired" })
      .refine(
        (value) => {
          const parsed = Number(value);
          return Number.isInteger(parsed) && parsed >= 1;
        },
        { message: "catalog.validation.durationInvalid" },
      ),
    features: z.array(z.string()),
    icon: z.string(),
    minPrice: z
      .string()
      .min(1, { message: "catalog.validation.minPriceRequired" })
      .refine(isNonNegativeAmount, {
        message: "catalog.validation.priceInvalid",
      }),
    maxPrice: z
      .string()
      .min(1, { message: "catalog.validation.maxPriceRequired" })
      .refine(isNonNegativeAmount, {
        message: "catalog.validation.priceInvalid",
      }),
  })
  // Reported on maxPrice so the caption lands under the field the admin should
  // fix — the backend blames the same one.
  .refine((values) => Number(values.maxPrice) >= Number(values.minPrice), {
    message: "catalog.validation.maxBelowMin",
    path: ["maxPrice"],
  });

export type WashPackageFormValues = z.infer<typeof washPackageSchema>;

// ─── Provider Price Schema ───────────────────────────────────────────────────

/**
 * The price a provider charges for one catalog package.
 *
 * The allowed range is per-package, so the schema is built per dialog rather
 * than declared once. The backend check is inclusive on both ends
 * (`price < minPrice || price > maxPrice` → 400), and this mirrors it so the
 * user is told before the request goes out.
 *
 * The bounds can't be interpolated into the message (FormField resolves keys
 * with no params), so the dialog shows the range as the field description.
 */
export function createProviderPriceSchema(minPrice: number, maxPrice: number) {
  return z.object({
    price: z
      .string()
      .min(1, { message: "catalog.validation.priceRequired" })
      .refine(
        (value) => {
          const parsed = Number(value);
          return (
            Number.isFinite(parsed) && parsed >= minPrice && parsed <= maxPrice
          );
        },
        { message: "catalog.validation.priceOutOfRange" },
      ),
  });
}

export type ProviderPriceFormValues = z.infer<
  ReturnType<typeof createProviderPriceSchema>
>;
