// Validation middleware for API routes
import { NextApiRequest, NextApiResponse } from 'next';
import { z, ZodSchema } from 'zod';

export function validateRequest(schema: {
  body?: ZodSchema;
  query?: ZodSchema;
  params?: ZodSchema;
}) {
  return function(handler: (req: NextApiRequest, res: NextApiResponse) => Promise<void>) {
    return async (req: NextApiRequest, res: NextApiResponse) => {
      try {
        // Validate request body
        if (schema.body && req.body) {
          req.body = schema.body.parse(req.body);
        }
        
        // Validate query parameters
        if (schema.query && req.query) {
          req.query = schema.query.parse(req.query);
        }
        
        // Validate route parameters (if needed)
        if (schema.params) {
          // Extract params from URL if needed
          // This would need custom implementation based on your routing
        }
        
        return handler(req, res);
      } catch (error: any) {
        if (error.name === 'ZodError') {
          return res.status(400).json({
            success: false,
            error: 'Validation error',
            details: error.errors.map((err: any) => ({
              field: err.path.join('.'),
              message: err.message,
              code: err.code,
            })),
            code: 'VALIDATION_ERROR'
          });
        }
        
        throw error; // Re-throw non-validation errors
      }
    };
  };
}

// Common validation schemas
export const commonSchemas = {
  id: z.object({
    id: z.string().transform(val => parseInt(val)).refine(val => !isNaN(val), {
      message: 'ID must be a valid number'
    })
  }),
  
  pagination: z.object({
    page: z.string().optional().transform(val => val ? parseInt(val) : 1),
    limit: z.string().optional().transform(val => val ? parseInt(val) : 10),
    orderBy: z.string().optional().default('id'),
    orderDirection: z.enum(['ASC', 'DESC']).optional().default('DESC'),
  }),
  
  search: z.object({
    search: z.string().optional(),
    searchFields: z.array(z.string()).optional(),
  }),
  
  dateRange: z.object({
    startDate: z.string().datetime().optional(),
    endDate: z.string().datetime().optional(),
  }),
};

// Sanitization helpers
export const sanitize = {
  // Remove HTML tags and dangerous characters
  html: (input: string): string => {
    return input.replace(/<[^>]*>/g, '').trim();
  },
  
  // Sanitize phone number
  phone: (input: string): string => {
    return input.replace(/[^\d+\-\s()]/g, '').trim();
  },
  
  // Sanitize email
  email: (input: string): string => {
    return input.toLowerCase().trim();
  },
  
  // Sanitize name (allow letters, spaces, hyphens, apostrophes)
  name: (input: string): string => {
    return input.replace(/[^a-zA-Z\s\-']/g, '').trim();
  },
};

// Custom validation rules
export const customValidations = {
  // Indian phone number validation
  indianPhone: z.string().refine(
    (phone) => /^(\+91|91)?[6-9]\d{9}$/.test(phone.replace(/[\s\-()]/g, '')),
    { message: 'Invalid Indian phone number' }
  ),
  
  // Strong password validation
  strongPassword: z.string().min(8).refine(
    (password) => /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/.test(password),
    { message: 'Password must contain at least 8 characters with uppercase, lowercase, number and special character' }
  ),
  
  // Positive decimal validation
  positiveDecimal: z.number().positive().multipleOf(0.01),
  
  // Future date validation
  futureDate: z.string().datetime().refine(
    (date) => new Date(date) > new Date(),
    { message: 'Date must be in the future' }
  ),
  
  // Past date validation
  pastDate: z.string().datetime().refine(
    (date) => new Date(date) <= new Date(),
    { message: 'Date cannot be in the future' }
  ),
};

// File upload validation
export const fileValidation = {
  image: z.object({
    filename: z.string(),
    mimetype: z.string().refine(
      (type) => type.startsWith('image/'),
      { message: 'File must be an image' }
    ),
    size: z.number().max(5 * 1024 * 1024, 'File size must be less than 5MB'),
  }),
  
  document: z.object({
    filename: z.string(),
    mimetype: z.string().refine(
      (type) => ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'].includes(type),
      { message: 'File must be PDF or Word document' }
    ),
    size: z.number().max(10 * 1024 * 1024, 'File size must be less than 10MB'),
  }),
};
