import { z } from "zod";
import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";

extendZodWithOpenApi(z);

export const ProductListQuerySchema = z.object({
  page: z.coerce.number().int().min(1).optional().default(1).openapi({
    example: 1,
    description: "Página actual",
  }),

  limit: z.coerce
    .number()
    .int()
    .min(1)
    .max(100)
    .optional()
    .default(20)
    .openapi({
      example: 20,
      description: "Cantidad de registros por página. Máximo 100.",
    }),

  // Búsqueda general
  search: z.string().trim().max(150).optional().openapi({
    example: "laptop",
    description:
      "Búsqueda general por nombre, código interno o código fabricante",
  }),

  // Filtros específicos
  nombre: z.string().trim().max(150).optional().openapi({
    example: "laptop",
    description: "Filtra por similitud en el nombre del producto",
  }),

  codInterno: z.string().trim().max(100).optional().openapi({
    example: "PROD-001",
    description: "Filtra por similitud en código interno",
  }),

  codFabricante: z.string().trim().max(100).optional().openapi({
    example: "FAB-001",
    description: "Filtra por similitud en código de fabricante",
  }),

  udnId: z.coerce.number().int().positive().optional().openapi({
    example: 1,
    description: "ID de unidad de negocio",
  }),

  marcaId: z.coerce.number().int().positive().optional().openapi({
    example: 5,
    description: "ID de marca",
  }),

  categoriaId: z.coerce.number().int().positive().optional().openapi({
    example: 10,
    description: "ID de categoría",
  }),

  sort: z
    .enum([
      "productoId",
      "codInterno",
      "codFabricante",
      "nombreProducto",
      "precioVenta",
    ])
    .optional()
    .default("nombreProducto")
    .openapi({
      example: "nombreProducto",
      description: "Campo usado para ordenar",
    }),

  order: z.enum(["asc", "desc"]).optional().default("asc").openapi({
    example: "asc",
    description: "Dirección del ordenamiento",
  }),
});

export const ProductIdParamSchema = z.object({
  id: z.coerce.number().int().positive().openapi({
    example: 123,
    description: "ID del producto",
  }),
});

export const ProductCodeParamSchema = z.object({
  code: z.string().trim().min(1).max(100).openapi({
    example: "LAPTOP-001",
    description:
      "Texto para buscar por similitud en código interno, código fabricante o nombre",
  }),
});

/**
 * Mantén este schema solo si vas a usar la ruta:
 * GET /products/search/:term
 *
 * Si NO vas a usar esa ruta, puedes borrarlo.
 */
export const ProductSearchParamSchema = z.object({
  term: z.string().trim().min(1).max(150).openapi({
    example: "laptop",
    description:
      "Texto a buscar por código interno, código fabricante o nombre",
  }),
});

export const ProductResponseSchema = z.object({
  id: z.number().openapi({ example: 123 }),

  codigos: z.object({
    interno: z.string().nullable().openapi({ example: "ABC123" }),
    fabricante: z.string().nullable().openapi({ example: "FAB-99" }),
  }),

  nombre: z.string().nullable().openapi({
    example: "Producto ejemplo",
  }),

  descripcion: z.string().nullable().openapi({
    example: "Descripción del producto",
  }),

  clasificacionMG: z.string().nullable().openapi({
    example: "A",
  }),

  estado: z.string().nullable().openapi({
    example: "Activo",
  }),

  precio: z.object({
    precioVentaSinIva: z.number().openapi({ example: 100 }),
    precioVentaConIva: z.number().openapi({ example: 113 }),
    ivaRate: z.number().openapi({ example: 0.13 }),
  }),

  marca: z
    .object({
      id: z.number().openapi({ example: 5 }),
      nombre: z.string().nullable().openapi({ example: "Marca X" }),
      abreviatura: z.string().nullable().openapi({ example: "MX" }),
      logo: z.string().nullable().openapi({ example: null }),
      estado: z.string().nullable().openapi({ example: "Activa" }),
    })
    .nullable(),

  unidadNegocio: z
    .object({
      id: z.number().openapi({ example: 1 }),
      nombre: z.string().nullable().openapi({ example: "UDN ejemplo" }),
      abreviatura: z.string().nullable().openapi({ example: "UDN" }),
      logo: z.string().nullable().openapi({ example: null }),
      estado: z.string().nullable().openapi({ example: "Activa" }),
    })
    .nullable(),

  unidadMedida: z
    .object({
      id: z.number().openapi({ example: 2 }),
      codigoMH: z.string().nullable().openapi({ example: "59" }),
      nombre: z.string().nullable().openapi({ example: "Unidad" }),
      abreviatura: z.string().nullable().openapi({ example: "UND" }),
    })
    .nullable(),

  tipoProducto: z
    .object({
      id: z.number().openapi({ example: 1 }),
      nombre: z.string().nullable().openapi({ example: "Producto terminado" }),
    })
    .nullable(),

  paisOrigen: z
    .object({
      id: z.number().openapi({ example: 68 }),
      nombre: z.string().nullable().openapi({ example: "El Salvador" }),
      abreviatura: z.string().nullable().openapi({ example: "SV" }),
    })
    .nullable(),

  categorias: z.array(
    z.object({
      id: z.number().openapi({ example: 10 }),
      nombre: z.string().nullable().openapi({ example: "Computadoras" }),
      abreviatura: z.string().nullable().openapi({ example: "COMP" }),
    }),
  ),

  especificaciones: z.array(
    z.object({
      id: z.number().openapi({ example: 1 }),
      catalogoId: z.number().nullable().openapi({ example: 20 }),
      tipo: z.string().nullable().openapi({ example: "Técnica" }),
      nombre: z.string().nullable().openapi({ example: "Procesador" }),
      tipoMagnitud: z.string().nullable().openapi({ example: "Texto" }),
      valor: z.string().nullable().openapi({ example: "Intel Core i5" }),
      unidadMedida: z
        .object({
          id: z.number().openapi({ example: 2 }),
          nombre: z.string().nullable().openapi({ example: "Unidad" }),
          abreviatura: z.string().nullable().openapi({ example: "UND" }),
        })
        .nullable(),
    }),
  ),
  existencias: z.array(
    z.object({
      sucursalId: z.number().openapi({ example: 1 }),
      nombreSucursal: z.string().nullable().openapi({
        example: "Indupal Casa Matriz",
      }),
      existenciaTotal: z.number().openapi({ example: 14 }),
    }),
  ),
});

export const ProductListResponseSchema = z.object({
  success: z.literal(true),
  data: z.array(ProductResponseSchema),
  meta: z.object({
    page: z.number().openapi({ example: 1 }),
    limit: z.number().openapi({ example: 20 }),
    total: z.number().openapi({ example: 100 }),
    totalPages: z.number().openapi({ example: 5 }),
  }),
});

export const ProductSingleResponseSchema = z.object({
  success: z.literal(true),
  data: ProductResponseSchema,
});

export type ProductListQuery = z.infer<typeof ProductListQuerySchema>;
export type ProductIdParam = z.infer<typeof ProductIdParamSchema>;
export type ProductCodeParam = z.infer<typeof ProductCodeParamSchema>;
export type ProductSearchParam = z.infer<typeof ProductSearchParamSchema>;
