import { z } from 'zod';

/** Decimal quantities travel as strings over the wire to avoid float drift. Accepts numbers for convenience. */
export const DecimalString = z
  .union([z.string(), z.number()])
  .transform((v) => (typeof v === 'number' ? v.toString() : v.trim()))
  .refine((v) => /^-?\d+(\.\d+)?$/.test(v), { message: 'Must be a decimal number' });

export const PositiveDecimalString = DecimalString.refine((v) => Number(v) > 0, { message: 'Must be greater than zero' });
export const NonNegativeDecimalString = DecimalString.refine((v) => Number(v) >= 0, { message: 'Must be zero or greater' });

export const Uuid = z.string().uuid();
export const Code = z.string().trim().min(1).max(50).regex(/^[A-Za-z0-9._\-\/]+$/, 'Only letters, digits, . _ - / allowed');
export const DateOnly = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Expected YYYY-MM-DD');
export const IsoDateTime = z.string().datetime({ offset: true });

export const AddressSchema = z
  .object({
    line1: z.string().max(200).optional(),
    line2: z.string().max(200).optional(),
    city: z.string().max(100).optional(),
    region: z.string().max(100).optional(),
    postalCode: z.string().max(30).optional(),
    country: z.string().length(2).optional(), // ISO 3166-1 alpha-2
  })
  .partial();
export type Address = z.infer<typeof AddressSchema>;

export const ContactSchema = z.object({
  name: z.string().max(120),
  email: z.string().email().optional(),
  phone: z.string().max(40).optional(),
  role: z.string().max(60).optional(),
});
export type Contact = z.infer<typeof ContactSchema>;

export const PaginationQuery = z.object({
  page: z.coerce.number().int().min(1).default(1),
  pageSize: z.coerce.number().int().min(1).max(500).default(50),
  sort: z.string().max(100).optional(), // e.g. "createdAt:desc"
  q: z.string().max(200).optional(), // free text
});
export type PaginationQueryDto = z.infer<typeof PaginationQuery>;

export interface Paginated<T> {
  items: T[];
  page: number;
  pageSize: number;
  total: number;
}

export const IdParam = z.object({ id: Uuid });

/** Standard API error envelope */
export interface ApiError {
  statusCode: number;
  error: string;
  message: string;
  code?: string; // machine-readable, e.g. INSUFFICIENT_STOCK
  details?: unknown;
  requestId?: string;
}
