import { z } from "zod";
import { productStatusValues } from "../db/schema.js";

const positiveId = z.coerce.number().int().positive();
const optionalPositiveId = z.coerce
  .number()
  .int()
  .positive()
  .nullable()
  .optional();
const slug = z
  .string()
  .trim()
  .min(1)
  .max(280)
  .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Use a URL-safe slug");
const slugList = z.preprocess(
  (value) => {
    if (typeof value === "string")
      return value
        .split(",")
        .map((item) => item.trim())
        .filter(Boolean);
    return value;
  },
  z.array(z.string().trim().min(1).max(160)).optional(),
);

const numberList = z.array(z.coerce.number().int().positive()).default([]);
const queryBoolean = z.preprocess((value) => {
  if (value === undefined) return undefined;
  if (typeof value === "boolean") return value;
  if (typeof value === "string") {
    if (["true", "1", "yes"].includes(value.toLowerCase())) return true;
    if (["false", "0", "no"].includes(value.toLowerCase())) return false;
  }
  return value;
}, z.boolean().optional());

export const productListQuerySchema = z.object({
  q: z.string().trim().min(1).max(120).optional(),
  page: z.coerce.number().int().min(1).default(1),
  perPage: z.coerce.number().int().min(1).max(60).default(12),
  sort: z
    .enum([
      "newest",
      "oldest",
      "price_asc",
      "price_desc",
      "rating_desc",
      "popular",
      "name_asc",
    ])
    .default("newest"),
  brand: slugList,
  type: slugList,
  collection: slugList,
  frameShape: slugList,
  faceShape: slugList,
  gender: slugList,
  color: slugList,
  lens: slugList,
  occasion: slugList,
  ageGroup: slugList,
  size: slugList,
  status: z.preprocess(
    (value) => {
      if (typeof value === "string")
        return value
          .split(",")
          .map((item) => item.trim())
          .filter(Boolean);
      return value;
    },
    z.array(z.enum(productStatusValues)).optional(),
  ),
  minPrice: z.coerce.number().int().min(0).optional(),
  maxPrice: z.coerce.number().int().min(0).optional(),
  rating: z.coerce.number().min(1).max(5).optional(),
  inStock: queryBoolean,
  featured: queryBoolean,
});

export const productSlugParamSchema = z.object({
  slug,
});

export const productIdParamSchema = z.object({
  id: positiveId,
});

const mediaInputSchema = z.object({
  url: z.string().trim().min(1).max(512),
  storageKey: z.string().trim().max(1024).nullable().optional(),
  fileName: z.string().trim().max(255).nullable().optional(),
  mimeType: z.string().trim().max(120).nullable().optional(),
  sizeBytes: z.coerce.number().int().min(0).nullable().optional(),
  altText: z.string().trim().max(255).nullable().optional(),
  sortOrder: z.coerce.number().int().min(0).default(0),
  isPrimary: z.boolean().default(false),
});

export const createProductSchema = z.object({
  sku: z.string().trim().min(1).max(80),
  name: z.string().trim().min(2).max(255),
  slug: slug.optional(),
  description: z.string().trim().max(5000).nullable().optional(),
  brandId: optionalPositiveId,
  productTypeId: optionalPositiveId,
  collectionId: optionalPositiveId,
  frameShapeId: optionalPositiveId,
  frameColorId: optionalPositiveId,
  ageGroupId: optionalPositiveId,
  sizeId: optionalPositiveId,
  basePrice: z.coerce.number().int().min(0),
  discountPercent: z.coerce.number().int().min(0).max(100).default(0),
  salePrice: z.coerce.number().int().min(0).optional(),
  stockQuantity: z.coerce.number().int().min(0).default(0),
  status: z.enum(productStatusValues).default("draft"),
  isFeatured: z.boolean().default(false),
  genderIds: numberList,
  faceShapeIds: numberList,
  lensFeatureIds: numberList,
  occasionIds: numberList,
  media: z.array(mediaInputSchema).default([]),
});

export const updateProductSchema = createProductSchema
  .partial()
  .extend({
    genderIds: numberList.optional(),
    faceShapeIds: numberList.optional(),
    lensFeatureIds: numberList.optional(),
    occasionIds: numberList.optional(),
    media: z.array(mediaInputSchema).optional(),
  })
  .refine(
    (value) => Object.keys(value).length > 0,
    "At least one field is required",
  );
