<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\ApplicationSystem;

use Doctrine\Common\Collections\Collection;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Enum\AttendanceStatus;
use Ferienpass\CoreBundle\Enum\AttendanceTransition;

class FirstComeApplicationSystem extends AbstractApplicationSystem
{
    public static function getType(): string
    {
        return self::FIRSTCOME;
    }

    protected function doGetTransitionName(Attendance $attendance): ?string
    {
        $offer = $attendance->getOffer();
        $currentStatus = $attendance->getStatus();

        // Only assign attendance status for waitlisted or new attendances.
        // All other attendance statuses (confirmed, error, withdrawn,…) are persistent.
        if (AttendanceStatus::WAITING !== $currentStatus && !$attendance->isWaitlisted()) {
            return null;
        }

        $max = $offer->getMaxParticipants();

        // Offers with no participant limit
        if (!$max) {
            return AttendanceTransition::CONFIRM;
        }

        $attendances = $offer->getAttendancesConfirmedOrWaitlisted();
        $position = $this->calculatePosition($attendance, $attendances);

        // Existing participant and spots left
        if (null !== $position && $position < $max) {
            return AttendanceTransition::CONFIRM;
        }

        // New participant and spots left
        if (null === $position && $attendances->count() < $max) {
            return AttendanceTransition::CONFIRM;
        }

        return AttendanceTransition::WAITLIST;
    }

    /**
     * Calculate the position of a participant in the participant list.
     * Returns NULL for new participants and the integer position (0 = first)
     * for existing participants on the list.
     */
    private function calculatePosition(Attendance $attendance, Collection $collection): ?int
    {
        if ($collection->isEmpty()) {
            return null;
        }

        $i = 0;
        foreach ($collection as $a) {
            if ($a->getParticipant() === $attendance->getParticipant()) {
                return $i;
            }

            ++$i;
        }

        return null;
    }
}
