/**
 * Example of custom error messages with type-compiler
 * 
 * This example demonstrates how to configure and use custom error messages
 * with different validation rules and how they appear in runtime errors.
 */

import { z } from 'zod';

// These interfaces will have their Zod schemas generated by type-compiler
// The validation rules and custom error messages are defined in tsconfig.json

interface User {
  id: string;
  name: string;
  email: string; // Will use custom error message for email format
  role: string;  // Will use custom error message for allowed roles
  age: number;   // Will use custom error message for age range
}

interface Product {
  id: string;
  name: string;
  price: number;  // Will use custom error message for minimum price
  inventory: number; // Will use custom error message for non-negative inventory
}

// This would be generated by type-compiler at build time
// Included here to demonstrate expected output
// Using proper Zod method chaining - setErrorMap is typically what Zod uses
// for custom error messages rather than a .message() method
const zUser = z.object({
  id: z.string().uuid().describe("ID must be a valid UUID"),
  name: z.string().min(2).describe("Name must be at least 2 characters"),
  email: z.string().email().describe("Company email must end with @company.com"),
  role: z.enum(['admin', 'user', 'guest']).describe("Role must be one of: admin, user, or guest"),
  age: z.number().int().min(18).max(120).describe("Age must be between 18 and 120")
});

const zProduct = z.object({
  id: z.string().uuid().describe("ID must be a valid UUID"),
  name: z.string().min(1),
  price: z.number().positive().min(0.01).describe("Price must be greater than $0.01"),
  inventory: z.number().int().min(0).describe("Inventory must be a non-negative integer")
});

// Custom error formatting function that uses the descriptions as error messages
const customErrorMap: z.ZodErrorMap = (issue, ctx) => {
  // If we have a custom description, use it as the error message
  if (ctx.data?.description) {
    return { message: ctx.data.description };
  }
  // Otherwise fall back to default error message
  return { message: ctx.defaultError };
};

// Set the custom error map
z.setErrorMap(customErrorMap);

/**
 * Validates user data with helpful error messages
 */
function validateUser(userData: unknown): User {
  try {
    return zUser.parse(userData);
  } catch (error) {
    if (error instanceof z.ZodError) {
      console.error("Validation failed with custom error messages:");
      error.errors.forEach(err => {
        console.error(`- ${err.path.join('.')}: ${err.message}`);
      });
    }
    throw error;
  }
}

/**
 * Validates product data with helpful error messages
 */
function validateProduct(productData: unknown): Product {
  try {
    return zProduct.parse(productData);
  } catch (error) {
    if (error instanceof z.ZodError) {
      console.error("Validation failed with custom error messages:");
      error.errors.forEach(err => {
        console.error(`- ${err.path.join('.')}: ${err.message}`);
      });
    }
    throw error;
  }
}

// Example usage
function main() {
  console.log("=== Custom Error Messages Example ===\n");
  
  // Valid user example
  try {
    const validUserData = {
      id: "123e4567-e89b-12d3-a456-426614174000",
      name: "Jane Smith",
      email: "jane@company.com",
      role: "admin" as const,
      age: 35
    };
    
    const validUser = validateUser(validUserData);
    console.log("Valid user:", validUser);
  } catch (error) {
    // This shouldn't execute for valid data
  }
  
  console.log("\n=== Invalid User Example ===\n");
  
  // Invalid user example
  try {
    const invalidUserData = {
      id: "invalid-uuid",
      name: "J",
      email: "jane@gmail.com", // Not a company email
      role: "manager",         // Not in allowed roles
      age: 16                  // Below minimum age
    };
    
    validateUser(invalidUserData);
  } catch (error) {
    // The validation should fail with helpful custom messages
    console.log("Expected validation failure with custom messages\n");
  }
  
  console.log("\n=== Invalid Product Example ===\n");
  
  // Invalid product example
  try {
    const invalidProductData = {
      id: "123",
      name: "Laptop",
      price: 0,           // Zero price
      inventory: -5       // Negative inventory
    };
    
    validateProduct(invalidProductData);
  } catch (error) {
    // The validation should fail with helpful custom messages
    console.log("Expected validation failure with custom messages\n");
  }
}

// Run the example
main(); 