<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Commerce\Catalog\Api\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use CpCreation\VitiCore\Commerce\Catalog\Api\Resource\CatalogChangeResource;
use CpCreation\VitiCore\Commerce\Catalog\CatalogContract;
use CpCreation\VitiCore\Commerce\Catalog\Model\CatalogChange;
use CpCreation\VitiCore\Commerce\Catalog\Repository\CatalogChangeRepository;

/**
 * @implements ProviderInterface<CatalogChangeResource>
 */
final readonly class CatalogChangeProvider implements ProviderInterface
{
    public function __construct(private CatalogChangeRepository $repository) {}

    /**
     * @return list<CatalogChangeResource>
     */
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
    {
        $filters = \is_array($context['filters'] ?? null) ? $context['filters'] : [];
        $after = $this->integer($filters['after'] ?? 0, 0, 0, \PHP_INT_MAX);
        $limit = $this->integer($filters['limit'] ?? 100, 100, 1, 250);

        return array_map($this->project(...), $this->repository->findAfterCursor($after, $limit));
    }

    private function project(CatalogChange $change): CatalogChangeResource
    {
        return new CatalogChangeResource(
            schema_version: CatalogContract::SCHEMA_VERSION,
            cursor: $change->getCursor(),
            event_id: $change->getEventId()->toString(),
            instance_id: $change->getInstanceId()->toString(),
            type: $change->getType()->value,
            resource_type: $change->getResourceType()->value,
            resource_id: $change->getResourceId(),
            occurred_at: $change->getOccurredAt()
                ->setTimezone(new \DateTimeZone('UTC'))
                ->format(\DATE_ATOM),
        );
    }

    private function integer(mixed $value, int $default, int $minimum, int $maximum): int
    {
        if (!\is_int($value) && !(\is_string($value) && 1 === preg_match('/^\d+$/', $value))) {
            return $default;
        }

        return min($maximum, max($minimum, (int) $value));
    }
}
