// middleware/validation.js
'use strict';

const Joi = require('joi');

/**
 * Validation middleware factory
 * @param {Joi.Schema} schema - Joi validation schema
 * @param {string} property - Property to validate ('body', 'query', 'params')
 */
const validate = (schema, property = 'body') => {
  return (req, res, next) => {
    const { error, value } = schema.validate(req[property], {
      abortEarly: false,
      stripUnknown: true
    });

    if (error) {
      const errors = error.details.map(detail => ({
        field: detail.path.join('.'),
        message: detail.message
      }));

      return res.status(400).json({
        success: false,
        message: 'Validation error',
        errors
      });
    }

    // Replace request data with validated and sanitized data
    req[property] = value;
    next();
  };
};

// ============================================
// CUSTOMER VALIDATION SCHEMAS
// ============================================

const customerSchema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30),
  email: Joi.string().email().required(),
  password: Joi.string().min(8).pattern(new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)')),
  firstName: Joi.string().min(2).max(50).required(),
  lastName: Joi.string().min(2).max(50).required(),
  phone: Joi.string().pattern(/^(\+254|0)[17]\d{8}$/).messages({
    'string.pattern.base': 'Phone must be a valid Kenyan number (e.g., +254712345678 or 0712345678)'
  }),
  dateOfBirth: Joi.date().max('now'),
  gender: Joi.string().valid('male', 'female', 'other', 'prefer_not_to_say'),
  profileImage: Joi.string().uri(),
  isActive: Joi.boolean(),
  role: Joi.string().valid('customer', 'admin', 'vendor')
});

const customerUpdateSchema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30),
  email: Joi.string().email(),
  firstName: Joi.string().min(2).max(50),
  lastName: Joi.string().min(2).max(50),
  phone: Joi.string().pattern(/^(\+254|0)[17]\d{8}$/),
  dateOfBirth: Joi.date().max('now'),
  gender: Joi.string().valid('male', 'female', 'other', 'prefer_not_to_say'),
  profileImage: Joi.string().uri(),
  isActive: Joi.boolean()
});

// ============================================
// ADDRESS VALIDATION SCHEMAS
// ============================================

const addressSchema = Joi.object({
  addressType: Joi.string().valid('home', 'work', 'other').required(),
  addressLine1: Joi.string().min(5).max(200).required(),
  addressLine2: Joi.string().max(200).allow('', null),
  city: Joi.string().min(2).max(100).required(),
  county: Joi.string().min(2).max(100).required(),
  postalCode: Joi.string().max(20).allow('', null),
  country: Joi.string().default('Kenya'),
  isDefault: Joi.boolean().default(false),
  deliveryInstructions: Joi.string().max(500).allow('', null)
});

// ============================================
// PAYMENT VALIDATION SCHEMAS
// ============================================

const paymentSchema = Joi.object({
  orderId: Joi.number().integer().positive().required(),
  paymentMethod: Joi.string().valid('mpesa', 'card', 'bank_transfer', 'cash').required(),
  amount: Joi.number().positive().precision(2).required(),
  currency: Joi.string().length(3).uppercase().default('KES'),
  phoneNumber: Joi.string().pattern(/^(\+254|0)[17]\d{8}$/).when('paymentMethod', {
    is: 'mpesa',
    then: Joi.required(),
    otherwise: Joi.optional()
  }),
  transactionReference: Joi.string().max(100),
  notes: Joi.string().max(500).allow('', null)
});

const paymentMethodSchema = Joi.object({
  methodType: Joi.string().valid('mpesa', 'card', 'bank').required(),
  phoneNumber: Joi.string().pattern(/^(\+254|0)[17]\d{8}$/).when('methodType', {
    is: 'mpesa',
    then: Joi.required()
  }),
  cardLast4: Joi.string().length(4).pattern(/^\d+$/).when('methodType', {
    is: 'card',
    then: Joi.required()
  }),
  cardBrand: Joi.string().valid('visa', 'mastercard', 'amex').when('methodType', {
    is: 'card',
    then: Joi.required()
  }),
  expiryMonth: Joi.number().integer().min(1).max(12).when('methodType', {
    is: 'card',
    then: Joi.required()
  }),
  expiryYear: Joi.number().integer().min(new Date().getFullYear()).when('methodType', {
    is: 'card',
    then: Joi.required()
  }),
  bankName: Joi.string().when('methodType', {
    is: 'bank',
    then: Joi.required()
  }),
  accountNumber: Joi.string().when('methodType', {
    is: 'bank',
    then: Joi.required()
  }),
  isDefault: Joi.boolean().default(false)
});

// ============================================
// LOYALTY & REWARDS VALIDATION
// ============================================

const redeemPointsSchema = Joi.object({
  points: Joi.number().integer().positive().min(100).required(),
  rewardType: Joi.string().valid('discount', 'voucher', 'product').required(),
  orderId: Joi.number().integer().positive().when('rewardType', {
    is: 'discount',
    then: Joi.required(),
    otherwise: Joi.optional()
  })
});

// ============================================
// ORDER VALIDATION
// ============================================

const cancelOrderSchema = Joi.object({
  reason: Joi.string().min(10).max(500).required(),
  refundMethod: Joi.string().valid('original', 'wallet', 'mpesa').default('original')
});

// ============================================
// PREFERENCES VALIDATION
// ============================================

const preferencesSchema = Joi.object({
  emailNotifications: Joi.boolean(),
  smsNotifications: Joi.boolean(),
  pushNotifications: Joi.boolean(),
  marketingEmails: Joi.boolean(),
  orderUpdates: Joi.boolean(),
  language: Joi.string().valid('en', 'sw').default('en'),
  currency: Joi.string().length(3).uppercase().default('KES')
});

// ============================================
// PASSWORD VALIDATION
// ============================================

const passwordSchema = Joi.object({
  currentPassword: Joi.string().required(),
  newPassword: Joi.string()
    .min(8)
    .pattern(new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]'))
    .required()
    .messages({
      'string.pattern.base': 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character'
    }),
  confirmPassword: Joi.string().valid(Joi.ref('newPassword')).required().messages({
    'any.only': 'Passwords must match'
  })
});

// ============================================
// EXPORT VALIDATION MIDDLEWARE
// ============================================

const validateCustomer = validate(customerSchema);
const validateCustomerUpdate = validate(customerUpdateSchema);
const validateAddress = validate(addressSchema);
const validatePayment = validate(paymentSchema);
const validatePaymentMethod = validate(paymentMethodSchema);
const validateRedeemPoints = validate(redeemPointsSchema);
const validateCancelOrder = validate(cancelOrderSchema);
const validatePreferences = validate(preferencesSchema);
const validatePassword = validate(passwordSchema);

module.exports = {
  validate,
  validateCustomer,
  validateCustomerUpdate,
  validateAddress,
  validatePayment,
  validatePaymentMethod,
  validateRedeemPoints,
  validateCancelOrder,
  validatePreferences,
  validatePassword
};