/**
 * Domain Toolkit - Validation Helpers
 * 
 * Common validation utilities that can be reused across all domains.
 */

import { z } from "zod";

// ============================================================================
// ID Validation
// ============================================================================

/**
 * Validate that an ID is a positive integer
 */
export function isValidPositiveId(id: number): boolean {
  return Number.isInteger(id) && id > 0;
}

/**
 * Validate Salesforce ID (18 characters, alphanumeric)
 */
export function isValidSalesforceId(id: string): boolean {
  return /^[A-Za-z0-9]{18}$/.test(id);
}

// ============================================================================
// Pagination Validation
// ============================================================================

/**
 * Validate and sanitize pagination parameters
 */
export function sanitizePagination(options: {
  page?: number;
  limit?: number;
  minLimit?: number;
  maxLimit?: number;
  defaultLimit?: number;
}): {
  page: number;
  limit: number;
} {
  const {
    page = 1,
    limit = options.defaultLimit ?? 10,
    minLimit = 1,
    maxLimit = 100,
  } = options;

  return {
    page: Math.max(1, Math.floor(page)),
    limit: Math.max(minLimit, Math.min(maxLimit, Math.floor(limit))),
  };
}

/**
 * Check if pagination offset is valid
 */
export function isValidPaginationOffset(offset: number): boolean {
  return Number.isInteger(offset) && offset >= 0;
}

// ============================================================================
// String Validation
// ============================================================================

/**
 * Check if string is non-empty after trimming
 */
export function isNonEmptyString(value: unknown): value is string {
  return typeof value === "string" && value.trim().length > 0;
}

/**
 * Check if value is a valid enum member
 */
export function isValidEnumValue<T extends Record<string, string | number>>(
  value: unknown,
  enumObj: T
): value is T[keyof T] {
  return Object.values(enumObj).includes(value as any);
}

// ============================================================================
// Array Validation
// ============================================================================

/**
 * Check if array is non-empty
 */
export function isNonEmptyArray<T>(value: unknown): value is T[] {
  return Array.isArray(value) && value.length > 0;
}

/**
 * Check if all array items are unique
 */
export function hasUniqueItems<T>(items: T[]): boolean {
  return new Set(items).size === items.length;
}

// ============================================================================
// Number Validation
// ============================================================================

/**
 * Check if number is within range (inclusive)
 */
export function isInRange(
  value: number,
  min: number,
  max: number
): boolean {
  return value >= min && value <= max;
}

/**
 * Check if number is a valid positive integer
 */
export function isPositiveInteger(value: unknown): value is number {
  return typeof value === "number" && Number.isInteger(value) && value > 0;
}

/**
 * Check if number is a valid non-negative integer
 */
export function isNonNegativeInteger(value: unknown): value is number {
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
}

// ============================================================================
// Date Validation
// ============================================================================

/**
 * Check if string is a valid ISO date time
 */
export function isValidIsoDateTime(value: string): boolean {
  const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
  if (!isoRegex.test(value)) return false;

  const date = new Date(value);
  return !isNaN(date.getTime());
}

/**
 * Check if string is a valid date in YYYYMMDD format
 */
export function isValidYYYYMMDD(value: string): boolean {
  return /^\d{8}$/.test(value);
}

// ============================================================================
// Zod Schema Helpers
// ============================================================================

/**
 * Create a schema for a positive integer ID
 */
export const positiveIdSchema = z.number().int().positive();

/**
 * Create a schema for pagination parameters
 */
export function createPaginationSchema(options?: {
  minLimit?: number;
  maxLimit?: number;
  defaultLimit?: number;
}) {
  const { minLimit = 1, maxLimit = 100, defaultLimit = 10 } = options ?? {};

  return z.object({
    page: z.coerce.number().int().positive().optional().default(1),
    limit: z.coerce
      .number()
      .int()
      .min(minLimit)
      .max(maxLimit)
      .optional()
      .default(defaultLimit),
    offset: z.coerce.number().int().nonnegative().optional(),
  });
}

/**
 * Create a schema for sortable queries
 */
export const sortableQuerySchema = z.object({
  sortBy: z.string().optional(),
  sortOrder: z.enum(["asc", "desc"]).optional(),
});

// ============================================================================
// Type Guards
// ============================================================================

/**
 * Type guard for checking if value is a record
 */
export function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

/**
 * Type guard for checking if error is a Zod error
 */
export function isZodError(error: unknown): error is z.ZodError {
  return (
    typeof error === "object" &&
    error !== null &&
    "issues" in error &&
    Array.isArray((error as any).issues)
  );
}

