<?php

declare(strict_types=1);

namespace CliqThemes\UI\Data;

use ArrayIterator;
use IteratorAggregate;
use Traversable;

/**
 * Represents a paginated slice of data returned by a provider while remaining iterable.
 *
 * @implements IteratorAggregate<int,array<string,mixed>>
 */
final class PaginatedResult implements IteratorAggregate
{
    /**
     * @var array<int,array<string,mixed>>
     */
    private array $records;

    private int $total;

    private int $perPage;

    private int $page;

    public function __construct(array $records, int $total, int $perPage, int $page)
    {
        $this->records = array_values($records);
        $this->total = max(0, $total);
        $this->perPage = max(1, $perPage);
        $this->page = max(1, $page);
    }

    /**
     * Makes the result iterable so it can be used in foreach loops and higher-order functions.
     *
     * @return Traversable<int,array<string,mixed>>
     */
    public function getIterator(): Traversable
    {
        return new ArrayIterator($this->records);
    }

    /**
     * Returns the hydrated records for the current page.
     *
     * @return array<int,array<string,mixed>>
     */
    public function records(): array
    {
        return $this->records;
    }

    /**
     * Total number of records available across all pages.
     */
    public function total(): int
    {
        return $this->total;
    }

    /**
     * Number of records exposed per page.
     */
    public function perPage(): int
    {
        return $this->perPage;
    }

    /**
     * Current page index (1-based).
     */
    public function page(): int
    {
        return $this->page;
    }

    /**
     * Calculates the number of pages required to exhaust the result set.
     */
    public function totalPages(): int
    {
        if ($this->perPage <= 0) {
            return 0;
        }

        return (int) ceil($this->total / $this->perPage);
    }

    /**
     * Returns pagination metadata formatted for transport over the REST API.
     *
     * @return array<string,int>
     */
    public function pagination(): array
    {
        return [
            'total' => $this->total(),
            'per_page' => $this->perPage(),
            'page' => $this->page(),
            'total_pages' => $this->totalPages(),
        ];
    }
}
