import { z } from "zod";

/**
 * Common Zod schemas for reuse across the application
 */

/**
 * UUID schema with custom error message
 */
export const uuidSchema = (entityName: string = "ID") =>
	z
		.string({ message: `${entityName} inválido.` })
		.uuid(`${entityName} inválido.`);

/**
 * Decimal string schema - parses string with comma/period to number
 */
export const decimalSchema = z
	.string()
	.trim()
	.transform((value) => value.replace(/\s/g, "").replace(",", "."))
	.refine(
		(value) => !Number.isNaN(Number.parseFloat(value)),
		"Informe um valor numérico válido.",
	)
	.transform((value) => Number.parseFloat(value));

/**
 * Optional/nullable decimal string schema
 */
export const optionalDecimalSchema = z
	.string()
	.trim()
	.optional()
	.transform((value) =>
		value && value.length > 0 ? value.replace(",", ".") : null,
	)
	.refine(
		(value) => value === null || !Number.isNaN(Number.parseFloat(value)),
		"Informe um valor numérico válido.",
	)
	.transform((value) => (value === null ? null : Number.parseFloat(value)));

/**
 * Day of month schema (1-31)
 */
export const dayOfMonthSchema = z
	.string({ message: "Informe o dia." })
	.trim()
	.min(1, "Informe o dia.")
	.refine((value) => {
		const parsed = Number.parseInt(value, 10);
		return !Number.isNaN(parsed) && parsed >= 1 && parsed <= 31;
	}, "Informe um dia entre 1 e 31.");

/**
 * Period schema (YYYY-MM format)
 */
export const periodSchema = z
	.string({ message: "Informe o período." })
	.trim()
	.regex(/^\d{4}-(0[1-9]|1[0-2])$/, "Período inválido.");

/**
 * Optional period schema
 */
export const optionalPeriodSchema = z
	.string()
	.trim()
	.regex(/^(\d{4})-(\d{2})$/, {
		message: "Selecione um período válido.",
	})
	.optional();

/**
 * Date string schema
 */
export const dateStringSchema = z
	.string({ message: "Informe a data." })
	.trim()
	.refine((value) => !Number.isNaN(new Date(value).getTime()), {
		message: "Data inválida.",
	});

/**
 * Optional date string schema
 */
export const optionalDateStringSchema = z
	.string()
	.trim()
	.refine((value) => !value || !Number.isNaN(new Date(value).getTime()), {
		message: "Informe uma data válida.",
	})
	.optional();

/**
 * Note/observation schema (max 500 chars, trimmed, nullable)
 */
export const noteSchema = z
	.string()
	.trim()
	.max(500, "A anotação deve ter no máximo 500 caracteres.")
	.optional()
	.transform((value) => (value && value.length > 0 ? value : null));

/**
 * Optional string that becomes null if empty
 */
export const optionalStringToNull = z
	.string()
	.trim()
	.optional()
	.transform((value) => (value && value.length > 0 ? value : null));

/**
 * Required non-empty string schema
 */
export const requiredStringSchema = (fieldName: string) =>
	z
		.string({ message: `Informe ${fieldName}.` })
		.trim()
		.min(1, `Informe ${fieldName}.`);

/**
 * Amount schema with minimum value validation
 */
export const amountSchema = z.coerce
	.number({ message: "Informe o valor." })
	.min(0, "Informe um valor maior ou igual a zero.");

/**
 * Positive amount schema
 */
export const positiveAmountSchema = z.coerce
	.number({ message: "Informe o valor." })
	.positive("Informe um valor maior que zero.");
