<?php

declare(strict_types=1);

namespace App\Framework\Database\Repository;

/**
 * Value Object für paginierte Ergebnisse
 */
final readonly class PaginatedResult
{
    public function __construct(
        public array $items,
        public int $totalItems,
        public int $currentPage,
        public int $itemsPerPage,
        public int $totalPages
    ) {
        if ($currentPage < 1) {
            throw new \InvalidArgumentException('Current page must be at least 1');
        }

        if ($itemsPerPage < 1) {
            throw new \InvalidArgumentException('Items per page must be at least 1');
        }

        if ($totalItems < 0) {
            throw new \InvalidArgumentException('Total items cannot be negative');
        }

        if ($totalPages < 0) {
            throw new \InvalidArgumentException('Total pages cannot be negative');
        }
    }

    /**
     * Factory method für die Erstellung aus Query-Daten
     */
    public static function fromQuery(
        array $items,
        int $totalItems,
        int $page,
        int $limit
    ): self {
        $totalPages = (int) ceil($totalItems / $limit);

        return new self(
            items: $items,
            totalItems: $totalItems,
            currentPage: $page,
            itemsPerPage: $limit,
            totalPages: $totalPages
        );
    }

    /**
     * Prüft ob es eine nächste Seite gibt
     */
    public function hasNextPage(): bool
    {
        return $this->currentPage < $this->totalPages;
    }

    /**
     * Prüft ob es eine vorherige Seite gibt
     */
    public function hasPreviousPage(): bool
    {
        return $this->currentPage > 1;
    }

    /**
     * Berechnet den Offset für die aktuelle Seite
     */
    public function getOffset(): int
    {
        return ($this->currentPage - 1) * $this->itemsPerPage;
    }

    /**
     * Gibt die Range der angezeigten Items zurück (z.B. "1-10 of 100")
     */
    public function getDisplayRange(): string
    {
        if ($this->totalItems === 0) {
            return '0-0 of 0';
        }

        $start = $this->getOffset() + 1;
        $end = min($this->currentPage * $this->itemsPerPage, $this->totalItems);

        return "{$start}-{$end} of {$this->totalItems}";
    }

    /**
     * Konvertiert zu Array für JSON-Serialisierung
     */
    public function toArray(): array
    {
        return [
            'items' => $this->items,
            'pagination' => [
                'total_items' => $this->totalItems,
                'current_page' => $this->currentPage,
                'items_per_page' => $this->itemsPerPage,
                'total_pages' => $this->totalPages,
                'has_next_page' => $this->hasNextPage(),
                'has_previous_page' => $this->hasPreviousPage(),
                'display_range' => $this->getDisplayRange(),
            ],
        ];
    }
}
