// Input Validation Middleware
// Uses Zod for request validation

import { Request, Response, NextFunction } from 'express';
import { z, ZodError } from 'zod';
import { DbisError, ErrorCode } from '@/shared/types';
import { logger } from '@/infrastructure/monitoring/logger';

/**
 * Validation middleware factory
 * Creates middleware that validates request body, query, or params
 */
export function validateRequest(schema: {
  body?: z.ZodSchema<any>;
  query?: z.ZodSchema<any>;
  params?: z.ZodSchema<any>;
}) {
  return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      // Validate body
      if (schema.body) {
        req.body = await schema.body.parseAsync(req.body);
      }

      // Validate query
      if (schema.query) {
        req.query = await schema.query.parseAsync(req.query);
      }

      // Validate params
      if (schema.params) {
        req.params = await schema.params.parseAsync(req.params);
      }

      next();
    } catch (error) {
      if (error instanceof ZodError) {
        const errors = error.errors.map((err) => ({
          path: err.path.join('.'),
          message: err.message,
        }));

        logger.warn('Request validation failed', {
          path: req.path,
          method: req.method,
          errors,
        });

        next(
          new DbisError(
            ErrorCode.VALIDATION_ERROR,
            `Validation failed: ${errors.map((e) => e.message).join(', ')}`
          )
        );
        return;
      }

      next(error);
    }
  };
}

/**
 * Common validation schemas for IRU endpoints
 */
export const iruValidationSchemas = {
  // Marketplace
  inquiryRequest: z.object({
    offeringId: z.string().min(1, 'Offering ID is required'),
    organizationName: z.string().min(1, 'Organization name is required'),
    institutionalType: z.string().min(1, 'Institutional type is required'),
    jurisdiction: z.string().length(2, 'Jurisdiction must be a 2-letter country code'),
    contactEmail: z.string().email('Invalid email address'),
    contactPhone: z.string().optional(),
    contactName: z.string().min(1, 'Contact name is required'),
    estimatedVolume: z.string().optional(),
    expectedGoLive: z.string().datetime().optional().or(z.date().optional()),
  }),

  // Payment
  paymentRequest: z.object({
    subscriptionId: z.string().min(1, 'Subscription ID is required'),
    amount: z.number().positive('Amount must be positive'),
    currency: z.string().length(3, 'Currency must be a 3-letter code'),
    paymentMethod: z.enum(['stripe', 'braintree'], {
      errorMap: () => ({ message: 'Payment method must be stripe or braintree' }),
    }),
    paymentMethodId: z.string().min(1, 'Payment method ID is required'),
    description: z.string().optional(),
  }),

  // Deployment
  deploymentRequest: z.object({
    subscriptionId: z.string().min(1, 'Subscription ID is required'),
    deploymentConfig: z.record(z.any()).optional(),
  }),

  // Qualification
  qualificationRequest: z.object({
    inquiryId: z.string().min(1, 'Inquiry ID is required'),
    preliminaryInfo: z.record(z.any()).optional(),
  }),

  // Agreement
  agreementRequest: z.object({
    subscriptionId: z.string().min(1, 'Subscription ID is required'),
    templateId: z.string().optional(),
    variables: z.record(z.any()).optional(),
  }),

  // Notification
  notificationRequest: z.object({
    recipient: z.string().min(1, 'Recipient is required'),
    recipientType: z.enum(['email', 'sms', 'portal']),
    template: z.string().min(1, 'Template is required'),
    variables: z.record(z.any()),
    priority: z.enum(['low', 'normal', 'high', 'urgent']).optional(),
  }),

  // Common query params
  paginationQuery: z.object({
    limit: z.string().regex(/^\d+$/).transform(Number).pipe(z.number().min(1).max(100)).optional(),
    offset: z.string().regex(/^\d+$/).transform(Number).pipe(z.number().min(0)).optional(),
  }),

  // Common params
  idParam: z.object({
    id: z.string().min(1, 'ID is required'),
  }),
};
