<?php
/**
 * Result value object for {@see ListLogsUseCase::execute()}.
 *
 * Phase 11 slice 11d immutable VO that wraps the §12.2
 * `GET /affilun/v1/logs` response `data` shape documented in
 * `specifications/rest-api-spec.md`. The VO carries the masked
 * row slice (already projected by {@see LogMasker::maskRecord()})
 * plus the pagination axes echoed back from the originating
 * {@see \Affilun\Infrastructure\Persistence\LogListQuery}
 * so REST consumers can render the pagination envelope without
 * re-issuing the query.
 *
 * @package Affilun\Application\Logs\UseCase
 */

declare(strict_types=1);

namespace Affilun\Application\Logs\UseCase;

/**
 * Immutable result of {@see ListLogsUseCase::execute()}.
 *
 * See the file-level docblock for the §12.2 envelope shape and
 * the relationship between the contained items and the
 * {@see \Affilun\Application\Logs\LogMasker} pipeline.
 */
final class ListLogsResult {

	/**
	 * Masked row slice in newest-first order.
	 *
	 * @var list<array<string, mixed>>
	 */
	private array $items;

	/**
	 * Total matching rows across every page (after filtering,
	 * before pagination).
	 */
	private int $total;

	/**
	 * 1-based page number echoed back from the originating query.
	 */
	private int $page;

	/**
	 * Records per page echoed back from the originating query.
	 */
	private int $perPage;

	/**
	 * Total page count derived from `$total` / `$perPage`.
	 */
	private int $pageCount;

	/**
	 * Construct the result with explicit values for every axis.
	 *
	 * @param list<array<string, mixed>> $items     Masked row slice.
	 * @param int                        $total     Total matching rows (>= 0).
	 * @param int                        $page      1-based page number (>= 1).
	 * @param int                        $perPage   Records per page (>= 1).
	 * @param int                        $pageCount Total page count (>= 0).
	 */
	public function __construct(
		array $items,
		int $total,
		int $page,
		int $perPage,
		int $pageCount
	) {
		$this->items     = array_values( $items );
		$this->total     = $total;
		$this->page      = $page;
		$this->perPage   = $perPage;
		$this->pageCount = $pageCount;
	}

	/**
	 * Masked row slice in newest-first order.
	 *
	 * @return list<array<string, mixed>>
	 */
	public function items(): array {
		return $this->items;
	}

	/**
	 * Total matching rows across every page.
	 */
	public function total(): int {
		return $this->total;
	}

	/**
	 * 1-based page number echoed back from the originating query.
	 */
	public function page(): int {
		return $this->page;
	}

	/**
	 * Records per page echoed back from the originating query.
	 */
	public function perPage(): int {
		return $this->perPage;
	}

	/**
	 * Total page count derived from `$total` / `$perPage`.
	 */
	public function pageCount(): int {
		return $this->pageCount;
	}

	/**
	 * Render the §12.2 success envelope `data` shape:
	 *
	 *   `array(
	 *       'items'      => list<array<string, mixed>>,
	 *       'page'       => int,
	 *       'per_page'   => int,
	 *       'total'      => int,
	 *       'page_count' => int,
	 *   )`
	 *
	 * @return array{
	 *     items: list<array<string, mixed>>,
	 *     page: int,
	 *     per_page: int,
	 *     total: int,
	 *     page_count: int,
	 * }
	 */
	public function toArray(): array {
		return array(
			'items'      => $this->items,
			'page'       => $this->page,
			'per_page'   => $this->perPage,
			'total'      => $this->total,
			'page_count' => $this->pageCount,
		);
	}
}
