/**
 * User Management Validators
 *
 * Centralized validation logic for user management operations.
 * Provides reusable validation functions with clear error messages.
 *
 * @module validators/user-management
 */

import { ValidationRules, ErrorCodes, UserManagementError } from '@/lib/types/user-management.types';
import type {
  AccountStatusUpdate,
  CreateAdminNoteRequest,
  SendBillingEmailRequest,
  NoteCategory,
} from '@/lib/types/user-management.types';

// ============================================
// ACCOUNT STATUS VALIDATORS
// ============================================

/**
 * Validate account status update request
 *
 * @throws UserManagementError if validation fails
 */
export function validateAccountStatusUpdate(data: unknown): AccountStatusUpdate {
  const update = data as AccountStatusUpdate;

  // Validate action
  if (!update.action || !['suspend', 'activate'].includes(update.action)) {
    throw new UserManagementError(
      'Invalid action. Must be "suspend" or "activate"',
      ErrorCodes.INVALID_ACTION,
      400
    );
  }

  // Validate reason
  if (!update.reason || typeof update.reason !== 'string') {
    throw new UserManagementError(
      'Reason is required',
      ErrorCodes.INVALID_INPUT,
      400
    );
  }

  const trimmedReason = update.reason.trim();
  if (trimmedReason.length < ValidationRules.suspension.reasonMinLength) {
    throw new UserManagementError(
      `Reason must be at least ${ValidationRules.suspension.reasonMinLength} characters`,
      ErrorCodes.REASON_TOO_SHORT,
      400
    );
  }

  return {
    action: update.action,
    reason: trimmedReason,
  };
}

/**
 * Validate user can be suspended
 *
 * @throws UserManagementError if user cannot be suspended
 */
export function validateCanSuspend(user: { role: string }): void {
  if (user.role === 'ADMIN' || user.role === 'SUPER_ADMIN') {
    throw new UserManagementError(
      'Cannot suspend administrator accounts',
      ErrorCodes.CANNOT_SUSPEND_ADMIN,
      403
    );
  }
}

/**
 * Validate staff has permission to suspend
 *
 * @throws UserManagementError if staff lacks permission
 */
export function validateSuspendPermission(staffRole: string): void {
  if (staffRole !== 'ADMIN' && staffRole !== 'SUPER_ADMIN') {
    throw new UserManagementError(
      'Only administrators can modify account status',
      ErrorCodes.FORBIDDEN,
      403
    );
  }
}

// ============================================
// ADMIN NOTE VALIDATORS
// ============================================

/**
 * Validate admin note creation request
 *
 * @throws UserManagementError if validation fails
 */
export function validateAdminNoteRequest(data: unknown): CreateAdminNoteRequest {
  const request = data as CreateAdminNoteRequest;

  // Validate content
  if (!request.content || typeof request.content !== 'string') {
    throw new UserManagementError(
      'Note content is required',
      ErrorCodes.INVALID_INPUT,
      400
    );
  }

  const trimmedContent = request.content.trim();

  if (trimmedContent.length < ValidationRules.note.minLength) {
    throw new UserManagementError(
      `Note content must be at least ${ValidationRules.note.minLength} characters`,
      ErrorCodes.CONTENT_TOO_SHORT,
      400
    );
  }

  if (trimmedContent.length > ValidationRules.note.maxLength) {
    throw new UserManagementError(
      `Note content cannot exceed ${ValidationRules.note.maxLength} characters`,
      ErrorCodes.CONTENT_TOO_LONG,
      400
    );
  }

  // Validate category
  const validCategories: NoteCategory[] = [
    'GENERAL',
    'BILLING',
    'SUPPORT',
    'COMPLIANCE',
    'TECHNICAL',
    'SALES',
  ];

  const category = (request.category?.toUpperCase() as NoteCategory) || 'GENERAL';

  if (!validCategories.includes(category)) {
    throw new UserManagementError(
      `Invalid category. Must be one of: ${validCategories.join(', ')}`,
      ErrorCodes.INVALID_CATEGORY,
      400
    );
  }

  return {
    content: trimmedContent,
    category,
    isPrivate: request.isPrivate !== false, // Default to true
  };
}

// ============================================
// BILLING EMAIL VALIDATORS
// ============================================

/**
 * Validate billing email request
 *
 * @throws UserManagementError if validation fails
 */
export function validateBillingEmailRequest(data: unknown): SendBillingEmailRequest {
  const request = data as SendBillingEmailRequest;

  // Validate subject
  if (!request.subject || typeof request.subject !== 'string') {
    throw new UserManagementError(
      'Email subject is required',
      ErrorCodes.INVALID_INPUT,
      400
    );
  }

  const trimmedSubject = request.subject.trim();

  if (trimmedSubject.length < ValidationRules.billing.subjectMinLength) {
    throw new UserManagementError(
      `Subject must be at least ${ValidationRules.billing.subjectMinLength} characters`,
      ErrorCodes.CONTENT_TOO_SHORT,
      400
    );
  }

  if (trimmedSubject.length > ValidationRules.billing.subjectMaxLength) {
    throw new UserManagementError(
      `Subject cannot exceed ${ValidationRules.billing.subjectMaxLength} characters`,
      ErrorCodes.CONTENT_TOO_LONG,
      400
    );
  }

  // Validate content
  if (!request.content || typeof request.content !== 'string') {
    throw new UserManagementError(
      'Email content is required',
      ErrorCodes.INVALID_INPUT,
      400
    );
  }

  const trimmedContent = request.content.trim();

  if (trimmedContent.length < ValidationRules.billing.contentMinLength) {
    throw new UserManagementError(
      `Content must be at least ${ValidationRules.billing.contentMinLength} characters`,
      ErrorCodes.CONTENT_TOO_SHORT,
      400
    );
  }

  if (trimmedContent.length > ValidationRules.billing.contentMaxLength) {
    throw new UserManagementError(
      `Content cannot exceed ${ValidationRules.billing.contentMaxLength} characters`,
      ErrorCodes.CONTENT_TOO_LONG,
      400
    );
  }

  // Validate amount (if provided)
  if (request.amount !== undefined && request.amount !== null) {
    const amount = parseFloat(String(request.amount));
    if (isNaN(amount) || amount < 0) {
      throw new UserManagementError(
        'Invalid amount. Must be a positive number',
        ErrorCodes.INVALID_INPUT,
        400
      );
    }
  }

  // Validate due date (if provided)
  if (request.dueDate) {
    const dueDate = new Date(request.dueDate);
    if (isNaN(dueDate.getTime())) {
      throw new UserManagementError(
        'Invalid due date format',
        ErrorCodes.INVALID_INPUT,
        400
      );
    }
  }

  return {
    subject: trimmedSubject,
    content: trimmedContent,
    amount: request.amount,
    dueDate: request.dueDate,
  };
}

// ============================================
// PAGINATION VALIDATORS
// ============================================

/**
 * Validate and sanitize pagination parameters
 */
export function validatePagination(
  page?: number | string,
  limit?: number | string
): { page: number; limit: number } {
  // Parse and validate page
  const parsedPage = parseInt(String(page || '1'));
  const safePage = Math.max(1, isNaN(parsedPage) ? 1 : parsedPage);

  // Parse and validate limit
  const parsedLimit = parseInt(String(limit || ValidationRules.pagination.defaultLimit));
  const safeLimit = Math.min(
    ValidationRules.pagination.maxLimit,
    Math.max(1, isNaN(parsedLimit) ? ValidationRules.pagination.defaultLimit : parsedLimit)
  );

  return {
    page: safePage,
    limit: safeLimit,
  };
}

// ============================================
// GENERAL VALIDATORS
// ============================================

/**
 * Validate email format
 */
export function validateEmail(email: string): boolean {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

/**
 * Validate IP address format (IPv4)
 */
export function validateIPv4(ip: string): boolean {
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
  if (!ipRegex.test(ip)) return false;

  const octets = ip.split('.');
  return octets.every((octet) => {
    const num = parseInt(octet, 10);
    return num >= 0 && num <= 255;
  });
}

/**
 * Sanitize string input (trim and limit length)
 */
export function sanitizeString(
  input: string,
  maxLength: number = 1000
): string {
  return input.trim().slice(0, maxLength);
}

/**
 * Validate user role
 */
export function validateUserRole(role: string): role is UserRole {
  return ['CUSTOMER', 'STAFF', 'ADMIN', 'SUPER_ADMIN'].includes(role);
}

/**
 * Check if user has staff or higher role
 */
export function isStaffOrHigher(role: string): boolean {
  return ['STAFF', 'ADMIN', 'SUPER_ADMIN'].includes(role);
}

/**
 * Check if user has admin or higher role
 */
export function isAdminOrHigher(role: string): boolean {
  return ['ADMIN', 'SUPER_ADMIN'].includes(role);
}
