package de.avatic.lcc.repositories.pagination;

import java.util.List;
import java.util.function.Function;


/**
 * Represents the result of a search query with pagination, holding the list of results
 * and metadata related to the pagination (such as current page, total pages, and total elements).
 * <p>
 * A replacement for org.springframework.data.domain.Page, since this project uses spring jdbc
 *
 * @param <T> The type of the elements contained in the result.
 */
public class SearchQueryResult<T> {

    private final List<T> result;

    private final Integer page, totalPages, totalElements, elementsPerPage;

    /**
     * Constructs a new SearchQueryResult with the given result list and pagination metadata.
     *
     * @param result          The list of results for the query.
     * @param page            The current page number (0-indexed).
     * @param totalElements   The total number of elements across all pages.
     * @param elementsPerPage Elements on one page.
     */
    public SearchQueryResult(List<T> result, Integer page, Integer totalElements, Integer elementsPerPage) {
        this.result = result;
        this.page = page;
        this.totalPages = elementsPerPage == 0  ? 0 : (totalElements/elementsPerPage + (totalElements%elementsPerPage == 0 ? 0 : 1));
        this.totalElements = totalElements;
        this.elementsPerPage = elementsPerPage;
    }

    /**
     * Returns the list of results in this SearchQueryResult.
     *
     * @return The list of query results.
     */
    public List<T> toList() {
        return result;
    }


    /**
     * Returns the current page number of this SearchQueryResult (0-indexed).
     *
     * @return The current page number.
     */
    public int getPage() {
        return page;
    }


    /**
     * Returns the total number of pages in this SearchQueryResult.
     *
     * @return The total number of pages.
     */
    public int getTotalPages() {
        return totalPages;
    }

    /**
     * Returns the total number of elements in the search results.
     *
     * @return The total number of elements.
     */
    public int getTotalElements() {
        return totalElements;
    }

    public Integer getElementsPerPage() {
        return elementsPerPage;
    }

    public static <T, R> SearchQueryResult<T> map(SearchQueryResult<R> queryResult, Function<R, T> mapper) {
        return new SearchQueryResult<>(queryResult.toList().stream().map(mapper).toList(),
                                       queryResult.getPage(),
                                       queryResult.getTotalElements(),
                                       queryResult.getElementsPerPage());
    }
}
