import { z } from 'zod';

export interface PaginatedResponse<T> {
	items: T[];
	/** @description Total number of items. */
	total: number;
	/** @description Offset from the beginning of the query. */
	offset: number;
	/** @description Maximal number of items to send. */
	limit: number;
}

// Generic helper to coerce single values into arrays
export const arrayCoerce = <T extends z.ZodTypeAny>(schema: T) =>
	z
		.union([z.array(schema.or(z.any())), schema.or(z.any())])
		.transform((val) => (Array.isArray(val) ? val : [val]))
		.pipe(z.array(schema));

// Reusable schemas for coercing strings from strings or numbers
export const stringCoerce = z.union([z.string(), z.number()]).transform(String);
export const stringArrayCoerce = arrayCoerce(stringCoerce).nullable().optional();

// Search fields
export const searchQuerySchema = z.object({
	searchString: z.string().nullable().optional(),
	searchIgnoreCase: z.boolean().nullable().optional()
});

// Pagination fields
export const paginationQuerySchema = z.object({
	currentPage: z.coerce.number().optional(),
	pageSize: z.coerce.number().optional()
});

// Ordering fields
export const orderQuerySchema = z.object({
	orderBy: z.string().nullable().optional(),
	sortOrder: z.string().nullable().optional()
});

// Combined schema
export const commonQuerySchema = paginationQuerySchema
	.extend(searchQuerySchema.shape)
	.extend(orderQuerySchema.shape);
