<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Api\Provider;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Administration\Domain\Repository\HomeworkRulesHistoryRepository;
use App\Administration\Infrastructure\Api\Resource\HomeworkRulesHistoryResource;
use App\Shared\Infrastructure\Tenant\TenantContext;

use function is_string;
use function json_decode;

use const JSON_THROW_ON_ERROR;

use Override;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

/**
 * State Provider pour l'historique des modifications des règles de devoirs.
 *
 * @implements ProviderInterface<HomeworkRulesHistoryResource>
 */
final readonly class HomeworkRulesHistoryProvider implements ProviderInterface
{
    public function __construct(
        private HomeworkRulesHistoryRepository $historyRepository,
        private TenantContext $tenantContext,
        private AuthorizationCheckerInterface $authorizationChecker,
    ) {
    }

    /**
     * @return HomeworkRulesHistoryResource[]
     */
    #[Override]
    public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
    {
        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
            throw new AccessDeniedHttpException('Seuls les administrateurs peuvent voir l\'historique des règles.');
        }

        if (!$this->tenantContext->hasTenant()) {
            throw new UnauthorizedHttpException('Bearer', 'Tenant non défini.');
        }

        $rows = $this->historyRepository->findByTenant(
            $this->tenantContext->getCurrentTenantId(),
        );

        $resources = [];
        foreach ($rows as $row) {
            $resource = new HomeworkRulesHistoryResource();
            /** @var string $id */
            $id = $row['id'];
            $resource->id = $id;

            /** @var string|null $previousRules */
            $previousRules = $row['previous_rules'];
            if (is_string($previousRules)) {
                /** @var array<int, array{type: string, params: array<string, mixed>}> $decoded */
                $decoded = json_decode($previousRules, true, 512, JSON_THROW_ON_ERROR);
                $resource->previousRules = $decoded;
            }

            /** @var string $newRules */
            $newRules = $row['new_rules'];
            /** @var array<int, array{type: string, params: array<string, mixed>}> $decodedNew */
            $decodedNew = json_decode($newRules, true, 512, JSON_THROW_ON_ERROR);
            $resource->newRules = $decodedNew;

            /** @var string $enforcementMode */
            $enforcementMode = $row['enforcement_mode'];
            $resource->enforcementMode = $enforcementMode;
            $resource->enabled = (bool) $row['enabled'];

            /** @var string $changedBy */
            $changedBy = $row['changed_by'];
            $resource->changedBy = $changedBy;

            /** @var string $changedAt */
            $changedAt = $row['changed_at'];
            $resource->changedAt = $changedAt;

            $resources[] = $resource;
        }

        return $resources;
    }
}
