<?php

declare(strict_types=1);

namespace NoahVet\Reef\Business\Enumerator;

use NoahVet\Reef\Jane\Client;
use NoahVet\Reef\Jane\Exception\GetAllVeterinaryEstablishmentUserBadRequestException;
use NoahVet\Reef\Jane\Model\VeterinaryEstablishmentResponse;
use NoahVet\Reef\Jane\Model\VeterinaryEstablishmentUserResponse;

class VeterinaryEstablishmentTeamMembersEnumerator
{
    public function __construct(
        protected Client $client,
    ) {
    }

    /**
     * @param array{
     *     id?: string[],
     *     jobTitle?: string[],
     *     department?: string[],
     *     userId?: string[],
     *     veterinaryEstablishmentId?: string[],
     *     veterinaryServiceOptionId?: string[],
     *     fromCreatedDate?: string[],
     *     fromUpdatedDate?: string[],
     *     fromEntryDate?: string[],
     *     fromExitDate?: string[],
     *     fromServiceSubscriptionStartDate?: string[],
     *     fromServiceSubscriptionEndDate?: string[],
     *     toCreatedDate?: string[],
     *     toUpdatedDate?: string[],
     *     toEntryDate?: string[],
     *     toExitDate?: string[],
     *     toServiceSubscriptionStartDate?: string[],
     *     toServiceSubscriptionEndDate?: string[],
     *     sortCreatedDate?: string,
     *     sortUpdatedDatesortCreatedDate?: string,
     *     sortEntryDatesortCreatedDate?: string,
     *     sortExitDatesortCreatedDate?: string,
     *     sortJobTitlesortCreatedDate?: string
     *  } $filters
     *
     * @return \Generator<VeterinaryEstablishmentUserResponse>
     *
     * @see Client::getAllVeterinaryEstablishmentUser
     */
    public function enumerateAll(
        array $filters = [],
        int $querySize = 50,
    ): \Generator {
        for ($page = 0; true; ++$page) {
            try {
                $teamMembers = $this->client->getAllVeterinaryEstablishmentUser(
                    \array_merge($filters, ['page' => $page, 'limit' => $querySize]),
                );

                \assert(\is_array($teamMembers));

                foreach ($teamMembers as $teamMember) {
                    yield $teamMember;
                }

                if (\count($teamMembers) < $querySize) {
                    break;
                }
            } catch (GetAllVeterinaryEstablishmentUserBadRequestException) {
                // End of enumeration
                break;
            }
        }
    }

    /**
     * @param array<int, VeterinaryEstablishmentResponse> $establishments
     *
     * @return array<string, array<VeterinaryEstablishmentUserResponse>>
     */
    public function getTeamMembers(
        array $establishments,
        int $querySize = 50,
        ?\DateTimeImmutable $now = null,
    ): array {
        $nowStr = ($now ?? new \DateTimeImmutable())->format('c');
        $uuids = $this->extractUuids($establishments);

        $filters = [
            'veterinaryEstablishmentId' => $uuids,
            'toEntryDate' => [$nowStr, 'null'],
            'fromExitDate' => [$nowStr, 'null'],
        ];

        return \array_reduce(
            \iterator_to_array($this->enumerateAll($filters, $querySize)),
            function (array $carry, VeterinaryEstablishmentUserResponse $item): array {
                $establishmentId = $item->getVeterinaryEstablishment()?->getId();

                if (null !== $establishmentId) {
                    $carry[$establishmentId][] = $item;
                }

                return $carry;
            },
            [],
        );
    }

    /**
     * @param array<int, VeterinaryEstablishmentResponse> $establishments
     *
     * @return array<int, string>
     */
    protected function extractUuids(array $establishments): array
    {
        return \array_map(
            fn (VeterinaryEstablishmentResponse $est): string => $est->getId(),
            $establishments,
        );
    }
}
