<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Tools\Support;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

/**
 * 把 Eloquent 查询裁成白名单数组分页结果，禁止把 Paginator 泄漏到 Tool 输出。
 */
final class ToolPagedQuery
{
    /**
     * @param  array<string, mixed>  $input
     * @param  list<string>  $sortable
     * @return array{page: int, per_page: int, total: int, has_more: bool, rows: Collection<int, mixed>}
     */
    public static function paginate(
        Builder $query,
        array $input,
        array $sortable,
        string $defaultSort,
        string $defaultDir = 'desc',
    ): array {
        $page = max(1, (int) ($input['page'] ?? 1));
        $perPage = max(1, (int) ($input['per_page'] ?? 20));
        $sortBy = (string) ($input['sort_by'] ?? $defaultSort);
        if (! in_array($sortBy, $sortable, true)) {
            $sortBy = $defaultSort;
        }

        $sortDir = strtolower((string) ($input['sort_dir'] ?? $defaultDir));
        if ($sortDir !== 'asc' && $sortDir !== 'desc') {
            $sortDir = $defaultDir;
        }

        $qualifiedId = $query->getModel()->getQualifiedKeyName();
        if ($sortBy === 'id' || $sortBy === $query->getModel()->getKeyName()) {
            $sortBy = $qualifiedId;
        }

        $total = (int) (clone $query)->toBase()->getCountForPagination();
        $rows = (clone $query)
            ->orderBy($sortBy, $sortDir)
            ->orderBy($qualifiedId, $sortDir)
            ->forPage($page, $perPage)
            ->get();

        return [
            'page' => $page,
            'per_page' => $perPage,
            'total' => $total,
            'has_more' => self::hasMore($page, $perPage, $total),
            'rows' => $rows,
        ];
    }

    /**
     * @param  array{page?: int, per_page?: int, total?: int}  $page
     * @return array{page: int, per_page: int, total: int, has_more: bool}
     */
    public static function meta(array $page): array
    {
        $pageNumber = (int) ($page['page'] ?? 1);
        $perPage = (int) ($page['per_page'] ?? 20);
        $total = (int) ($page['total'] ?? 0);

        return [
            'page' => $pageNumber,
            'per_page' => $perPage,
            'total' => $total,
            'has_more' => self::hasMore($pageNumber, $perPage, $total),
        ];
    }

    public static function hasMore(int $page, int $perPage, int $total): bool
    {
        return $perPage > 0 && ($page * $perPage) < $total;
    }
}
