import Joi from 'joi';
import { Request, Response, NextFunction } from 'express';

/**
 * Esquemas de validación Joi para {{entity}}
 */

// Esquema base para campos comunes
const baseSchema = {
  id: Joi.string().uuid().required().description('Unique identifier for the {{entity}}'),
  createdAt: Joi.date().iso().required().description('Creation timestamp'),
  updatedAt: Joi.date().iso().required().description('Last update timestamp')
};

// Esquema para campos específicos de la entidad (personalizar según necesidades)
const entityFields = {
  // Ejemplo de campos - personalizar según la entidad
  // name: Joi.string().min(1).max(255).required().description('Name of the {{entity}}'),
  // description: Joi.string().max(1000).optional().description('Description of the {{entity}}'),
  // status: Joi.string().valid('active', 'inactive').default('active').description('Status of the {{entity}}')
};

/**
 * Esquema para crear {{entity}}
 */
export const create{{entity}}Schema = Joi.object({
  ...entityFields
  // Los campos específicos se definen en entityFields arriba
  // Ejemplo de uso:
  // name: Joi.string().min(1).max(255).required(),
  // description: Joi.string().max(1000).optional(),
  // status: Joi.string().valid('active', 'inactive').default('active')
}).options({ stripUnknown: true });

/**
 * Esquema para actualizar {{entity}}
 */
export const update{{entity}}Schema = Joi.object({
  // Todos los campos son opcionales para actualizaciones
  // Se crean versiones opcionales de los campos de entityFields
  // Ejemplo:
  // name: Joi.string().min(1).max(255).optional(),
  // description: Joi.string().max(1000).optional(),
  // status: Joi.string().valid('active', 'inactive').optional()
}).options({ stripUnknown: true });

/**
 * Interface para respuesta de {{entity}}
 */
export interface {{entity}}Response {
  id: string;
  createdAt: Date;
  updatedAt: Date;
  // Agregar campos específicos de la entidad aquí
  // Ejemplo:
  // name: string;
  // description?: string;
  // status: string;
}

/**
 * Esquema para búsqueda de {{entityPlural}}
 */
export const search{{entity}}Schema = Joi.object({
  search: Joi.string().max(255).optional().description('Search term'),
  page: Joi.number().integer().min(1).default(1).description('Page number'),
  limit: Joi.number().integer().min(1).max(100).default(10).description('Items per page'),
  sort: Joi.string().pattern(/^[a-zA-Z_][a-zA-Z0-9_]*:(asc|desc)$/).optional().description('Sort field and order (e.g., "createdAt:desc")'),
  filters: Joi.object().optional().description('Filter fields')
}).options({ stripUnknown: true });

/**
 * Interface para parámetros de búsqueda
 */
export interface Search{{entity}}Params {
  search?: string;
  page?: number;
  limit?: number;
  sort?: string;
  filters?: Record<string, any>;
}

/**
 * Interface para respuesta paginada de {{entityPlural}}
 */
export interface Paginated{{entity}}Response {
  data: {{entity}}Response[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrev: boolean;
  };
}

/**
 * Esquema para operaciones en lote
 */
export const bulk{{entity}}OperationSchema = Joi.object({
  operation: Joi.string().valid('create', 'update', 'delete').required().description('Operation type'),
  data: Joi.array().items(Joi.object()).min(1).required().description('Array of data for the operation'),
  options: Joi.object({
    skipDuplicates: Joi.boolean().default(false),
    continueOnError: Joi.boolean().default(false)
  }).optional().description('Options for the bulk operation')
}).options({ stripUnknown: true });

/**
 * Interface para operaciones en lote
 */
export interface Bulk{{entity}}Operation {
  operation: 'create' | 'update' | 'delete';
  data: any[];
  options?: {
    skipDuplicates?: boolean;
    continueOnError?: boolean;
  };
}

/**
 * Interface para respuesta de operación en lote
 */
export interface Bulk{{entity}}Response {
  success: boolean;
  processed: number;
  successful: number;
  failed: number;
  errors?: Array<{
    index: number;
    error: string;
    data?: any;
  }>;
  results?: {{entity}}Response[];
}

/**
 * Esquema para exportación de {{entityPlural}}
 */
export const export{{entity}}Schema = Joi.object({
  format: Joi.string().valid('json', 'csv', 'xlsx').default('json').description('Export format'),
  fields: Joi.array().items(Joi.string()).optional().description('Fields to include in export'),
  filters: Joi.object().optional().description('Filter criteria for export'),
  dateRange: Joi.object({
    from: Joi.date().iso().optional(),
    to: Joi.date().iso().optional()
  }).optional().description('Date range for export')
}).options({ stripUnknown: true });

/**
 * Interface para exportación de {{entityPlural}}
 */
export interface Export{{entity}}Params {
  format?: 'json' | 'csv' | 'xlsx';
  fields?: string[];
  filters?: Record<string, any>;
  dateRange?: {
    from?: string;
    to?: string;
  };
}

/**
 * Middleware de validación para usar con los esquemas Joi
 */
export const validateSchema = (schema: Joi.ObjectSchema) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = schema.validate(req.body);
    
    if (error) {
      return res.status(400).json({
        success: false,
        message: 'Validation failed',
        errors: error.details.map(detail => ({
          field: detail.path.join('.'),
          message: detail.message,
          value: detail.context?.value
        })),
        timestamp: new Date().toISOString()
      });
    }
    
    req.body = value;
    next();
  };
};

/**
 * Middleware de validación para query parameters
 */
export const validateQuery = (schema: Joi.ObjectSchema) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const { error, value } = schema.validate(req.query);
    
    if (error) {
      return res.status(400).json({
        success: false,
        message: 'Query validation failed',
        errors: error.details.map(detail => ({
          field: detail.path.join('.'),
          message: detail.message,
          value: detail.context?.value
        })),
        timestamp: new Date().toISOString()
      });
    }
    
    req.query = value;
    next();
  };
};