// Client-side UX validation only (docs/20-FRONTEND.md §3.1) — required fields,
// format/range checks the browser can already see. Server-authoritative rules
// (SKU uniqueness, master-in-use on delete, concurrency) are never
// re-implemented here; the server's ProblemDetails is the final word (§3.3).
// Hand-rolled (not zod) to match the plain-hooks posture most screens this
// session use — lib/validations/grn.ts is the one deliberate zod exception.

export function validateItemForm(input: {
  sku: string
  name: string
  categoryId: number | null
  baseUomId: number | null
  /** Raw field value; empty means "no measurable content", which is valid. */
  contentQty?: string
  contentUnit?: string | null
}): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!input.sku.trim()) errors.sku = "SKU is required"
  if (!input.name.trim()) errors.name = "Item name is required"
  if (!input.categoryId) errors.categoryId = "Select a category"
  if (!input.baseUomId) errors.baseUomId = "Select a base UOM"
  Object.assign(errors, contentPairErrors(input.contentQty, input.contentUnit))
  return errors
}

/**
 * An item's content size is optional, but half of it is not: the server rejects a lone
 * quantity or a lone unit with a 422. Shared because the variant builder validates its own
 * shape and so cannot go through `validateItemForm`.
 */
export function contentPairErrors(
  contentQty: string | undefined,
  contentUnit: string | null | undefined,
): Record<string, string> {
  const errors: Record<string, string> = {}
  const rawQty = (contentQty ?? "").trim()
  const unit = contentUnit ?? null

  if (rawQty && !unit) errors.contentUnit = "Select a unit for the content size"
  if (!rawQty && unit) errors.contentQty = "Enter a content size, or clear the unit"
  if (rawQty) {
    const qty = Number(rawQty)
    if (Number.isNaN(qty) || qty <= 0) errors.contentQty = "Content size must be greater than 0"
  }
  return errors
}

export function validateReorderLine(input: { warehouseId: number | null; reorderPoint: string; reorderQty: string }): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!input.warehouseId) errors.warehouseId = "Select a warehouse"
  const point = Number(input.reorderPoint)
  if (input.reorderPoint === "" || Number.isNaN(point) || point < 0) errors.reorderPoint = "Reorder point cannot be negative"
  const qty = Number(input.reorderQty)
  if (!input.reorderQty || Number.isNaN(qty) || qty <= 0) errors.reorderQty = "Reorder quantity must be greater than 0"
  return errors
}

export function validateUomName(name: string): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!name.trim()) errors.name = "UOM name is required"
  return errors
}

export function validateCategoryName(name: string): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!name.trim()) errors.name = "Category name is required"
  return errors
}

export function validateBrandName(name: string): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!name.trim()) errors.name = "Brand name is required"
  return errors
}

/** Renamed from validateVariantCategoryName — "variant categories" are Item Types now. */
export function validateItemTypeName(name: string): Record<string, string> {
  const errors: Record<string, string> = {}
  if (!name.trim()) errors.name = "Item type name is required"
  return errors
}

export function validateVariantItemForm(input: {
  productName: string
  categoryId: number | null
  hasVariants: boolean
}): Record<string, string> {
  const errors: Record<string, string> = {}
  // Required: it names every generated item and leads its SKU, and neither reads sensibly
  // when derived from the category instead ("Beverages - 500ml").
  if (!input.productName.trim()) errors.productName = "Enter a product name"
  if (!input.categoryId) errors.categoryId = "Select a category"
  if (!input.hasVariants) errors.variants = "Check at least one variant category and add its values"
  return errors
}

/**
 * Fixed-price mode requires every generated variant to carry a sale price > 0
 * (docs/20 §3.1). Returns a map keyed by variant key → message; empty when valid.
 * In "stock" mode there is nothing to validate (prices are sent as null).
 */
/**
 * Belt-and-braces sweep over the generated variants: each one's resolved content pair must be
 * whole or wholly absent. It should never fire — `addValue` rejects a half or duplicate pair at
 * entry — so it exists to catch stale state, not to guide the user.
 *
 * Keyed by variant key to mirror {@link validateVariantPrices}, but surfaced as ONE form-level
 * message: content is *derived*, so unlike a price there is no per-row control to attach an
 * error to.
 */
export function validateVariantContent(
  variantKeys: string[],
  contentFor: (key: string) => { qty: string; unit: string | null },
): Record<string, string> {
  const errors: Record<string, string> = {}
  for (const key of variantKeys) {
    const { qty, unit } = contentFor(key)
    const pair = contentPairErrors(qty, unit)
    const message = pair.contentQty ?? pair.contentUnit
    if (message) errors[key] = message
  }
  return errors
}

export function validateVariantPrices(
  variantKeys: string[],
  priceFor: (key: string) => string,
): Record<string, string> {
  const errors: Record<string, string> = {}
  for (const key of variantKeys) {
    const raw = priceFor(key).trim()
    const value = Number(raw)
    if (raw === "" || Number.isNaN(value) || value <= 0) {
      errors[key] = "Enter a price greater than 0"
    }
  }
  return errors
}
