<?php

declare(strict_types=1);

namespace App\Helpers;

/**
 * Paginator
 *
 * Framework-agnostic pagination over a PDO query. Every data table in
 * the frontend (Leads, Customers, Companies, Campaigns, Activity Logs,
 * ...) follows the same "Showing 1–20 of 220" + numbered page links
 * pattern — this class is the one place that logic lives.
 *
 * Usage:
 *   $paginator = Paginator::fromRequest($request, $perPage = 20);
 *   $countStmt = $pdo->prepare("SELECT COUNT(*) FROM leads WHERE ...");
 *   $countStmt->execute($bindings);
 *   $paginator->setTotal((int) $countStmt->fetchColumn());
 *
 *   $stmt = $pdo->prepare("SELECT * FROM leads WHERE ... LIMIT :limit OFFSET :offset");
 *   $stmt->bindValue('limit', $paginator->perPage(), PDO::PARAM_INT);
 *   $stmt->bindValue('offset', $paginator->offset(), PDO::PARAM_INT);
 *   ...
 *   echo json_encode(['data' => $rows, 'meta' => $paginator->meta()]);
 */
final class Paginator
{
    private int $page;
    private int $perPage;
    private int $total = 0;

    public function __construct(int $page = 1, int $perPage = 20, int $maxPerPage = 100)
    {
        $this->page = max(1, $page);
        $this->perPage = min(max(1, $perPage), $maxPerPage);
    }

    public static function fromRequest(\App\Core\Request $request, int $defaultPerPage = 20, int $maxPerPage = 100): self
    {
        $page = (int) $request->query('page', 1);
        $perPage = (int) $request->query('per_page', $defaultPerPage);

        return new self($page, $perPage, $maxPerPage);
    }

    public function setTotal(int $total): self
    {
        $this->total = max(0, $total);

        return $this;
    }

    public function page(): int
    {
        return $this->page;
    }

    public function perPage(): int
    {
        return $this->perPage;
    }

    public function offset(): int
    {
        return ($this->page - 1) * $this->perPage;
    }

    public function totalPages(): int
    {
        return $this->total === 0 ? 1 : (int) ceil($this->total / $this->perPage);
    }

    public function hasNextPage(): bool
    {
        return $this->page < $this->totalPages();
    }

    public function hasPreviousPage(): bool
    {
        return $this->page > 1;
    }

    /** Full metadata block, ready to drop straight into a JSON response or a view. */
    public function meta(): array
    {
        $from = $this->total === 0 ? 0 : $this->offset() + 1;
        $to = min($this->offset() + $this->perPage, $this->total);

        return [
            'page' => $this->page,
            'per_page' => $this->perPage,
            'total' => $this->total,
            'total_pages' => $this->totalPages(),
            'from' => $from,
            'to' => $to,
            'has_next' => $this->hasNextPage(),
            'has_previous' => $this->hasPreviousPage(),
        ];
    }
}
