<?php

namespace Signteer\Core\Action\Signup;

use Signteer\Core\Action\ActionResult;
use Signteer\Core\Event\EventBus;
use Signteer\Core\Event\Signup\SignupCreated;
use Signteer\Core\Criteria\TaskCriteria;
use Signteer\Core\Criteria\SignupCriteria;
use Signteer\Core\Criteria\VolunteerCriteria;
use Signteer\Core\Finder\TaskFinder;
use Signteer\Core\Finder\SignupFinder;
use Signteer\Core\Finder\VolunteerFinder;
use Signteer\Core\Writer\SignupWriter;

final class AssignVolunteer
{
    public $writer = SignupWriter::class;
    public $taskFinder = TaskFinder::class;
    public $signupFinder = SignupFinder::class;
    public $volunteerFinder = VolunteerFinder::class;
    public $eventBus = EventBus::class;

    public function __invoke(int $taskId, int $volunteerId): ActionResult
    {
        $ret = new ActionResult();

        $task = $this->taskFinder->get($taskId);
        if (!$task) {
            return $ret->addError('__Invalid task.__');
        }

        $totalSpots = $task->getSpots();

        $c = (new SignupCriteria())->whereTaskId('=', $taskId);
        $countExistingSignups = $this->signupFinder->count($c);

        if ($countExistingSignups >= $totalSpots) {
            return $ret->addError('__No spots available for new sign-ups.__');
        }

        $signupId = $this->writer->create($taskId, $volunteerId);

        $this->eventBus->emit(new SignupCreated($signupId));

        return $ret;
    }
}
