<?php

declare(strict_types=1);

namespace App\Administration\Application\Query\GetUsers;

use App\Administration\Application\Dto\PaginatedResult;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Domain\Model\User\StatutCompte;
use App\Administration\Domain\Repository\UserRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;

use function array_slice;
use function count;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler(bus: 'query.bus')]
final readonly class GetUsersHandler
{
    public function __construct(
        private UserRepository $userRepository,
        private Clock $clock,
    ) {
    }

    /**
     * @return PaginatedResult<UserDto>
     */
    public function __invoke(GetUsersQuery $query): PaginatedResult
    {
        $users = $this->userRepository->findAllByTenant(
            TenantId::fromString($query->tenantId),
        );

        if ($query->role !== null) {
            $filterRole = Role::tryFrom($query->role);
            if ($filterRole !== null) {
                $users = array_filter(
                    $users,
                    static fn ($user) => $user->aLeRole($filterRole),
                );
            }
        }

        if ($query->statut !== null) {
            $filterStatut = StatutCompte::tryFrom($query->statut);
            if ($filterStatut !== null) {
                $users = array_filter(
                    $users,
                    static fn ($user) => $user->statut === $filterStatut,
                );
            }
        }

        if ($query->search !== null && $query->search !== '') {
            $searchLower = mb_strtolower($query->search);
            $users = array_filter(
                $users,
                static fn ($user) => str_contains(mb_strtolower($user->firstName), $searchLower)
                    || str_contains(mb_strtolower($user->lastName), $searchLower)
                    || str_contains(mb_strtolower((string) $user->email), $searchLower),
            );
        }

        $users = array_values($users);
        $total = count($users);

        $offset = ($query->page - 1) * $query->limit;
        $items = array_slice($users, $offset, $query->limit);

        return new PaginatedResult(
            items: array_map(
                fn ($user) => UserDto::fromDomain($user, $this->clock),
                $items,
            ),
            total: $total,
            page: $query->page,
            limit: $query->limit,
        );
    }
}
