package com.gnx.telemedicine.util;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

/**
 * Utility class for pagination support.
 * Provides methods to create Pageable objects from request parameters.
 */
public class PaginationUtil {

    // Default values
    private static final int DEFAULT_PAGE = 0;
    private static final int DEFAULT_SIZE = 20;
    private static final int MAX_SIZE = 100;
    private static final int MIN_SIZE = 1;

    /**
     * Creates a Pageable object from page and size parameters.
     * 
     * @param page Page number (0-indexed)
     * @param size Page size
     * @return Pageable object
     */
    public static Pageable createPageable(Integer page, Integer size) {
        int pageNumber = page != null && page >= 0 ? page : DEFAULT_PAGE;
        int pageSize = size != null ? Math.min(Math.max(size, MIN_SIZE), MAX_SIZE) : DEFAULT_SIZE;
        
        return PageRequest.of(pageNumber, pageSize);
    }

    /**
     * Creates a Pageable object with sorting.
     * 
     * @param page Page number (0-indexed)
     * @param size Page size
     * @param sortBy Field to sort by
     * @param direction Sort direction (ASC or DESC)
     * @return Pageable object with sorting
     */
    public static Pageable createPageable(Integer page, Integer size, String sortBy, String direction) {
        int pageNumber = page != null && page >= 0 ? page : DEFAULT_PAGE;
        int pageSize = size != null ? Math.min(Math.max(size, MIN_SIZE), MAX_SIZE) : DEFAULT_SIZE;
        
        Sort sort = createSort(sortBy, direction);
        
        return PageRequest.of(pageNumber, pageSize, sort);
    }

    /**
     * Creates a Sort object from sort field and direction.
     * 
     * @param sortBy Field to sort by
     * @param direction Sort direction (ASC or DESC)
     * @return Sort object
     */
    public static Sort createSort(String sortBy, String direction) {
        if (sortBy == null || sortBy.isEmpty()) {
            return Sort.unsorted();
        }
        
        Sort.Direction sortDirection = Sort.Direction.ASC;
        if (direction != null && direction.equalsIgnoreCase("DESC")) {
            sortDirection = Sort.Direction.DESC;
        }
        
        // Sanitize sort field to prevent SQL injection
        String sanitizedSortBy = sanitizeSortField(sortBy);
        
        return Sort.by(sortDirection, sanitizedSortBy);
    }

    /**
     * Sanitizes sort field name to prevent SQL injection.
     * Only allows alphanumeric characters, underscores, and dots.
     * 
     * @param sortBy Sort field name
     * @return Sanitized sort field name
     */
    private static String sanitizeSortField(String sortBy) {
        if (sortBy == null || sortBy.isEmpty()) {
            return "id"; // Default sort field
        }
        
        // Remove any characters that are not alphanumeric, underscore, or dot
        String sanitized = sortBy.replaceAll("[^a-zA-Z0-9_.]", "");
        
        // If sanitization removed everything, use default
        if (sanitized.isEmpty()) {
            return "id";
        }
        
        return sanitized;
    }

    /**
     * Validates and sanitizes page number.
     * 
     * @param page Page number
     * @return Validated page number (0-indexed)
     */
    public static int validatePage(Integer page) {
        if (page == null || page < 0) {
            return DEFAULT_PAGE;
        }
        return page;
    }

    /**
     * Validates and sanitizes page size.
     * 
     * @param size Page size
     * @return Validated page size (between MIN_SIZE and MAX_SIZE)
     */
    public static int validateSize(Integer size) {
        if (size == null) {
            return DEFAULT_SIZE;
        }
        return Math.min(Math.max(size, MIN_SIZE), MAX_SIZE);
    }
}

