<?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\AdminBundle\Components;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\ApplicationSystem\ParticipantListFacade;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\Notification\AttendanceNotificationChecker;
use Ferienpass\CoreBundle\Repository\AttendanceRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\LiveComponent\ValidatableComponentTrait;
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;

#[AsLiveComponent(route: 'live_component_admin')]
class ChangeAttendanceStatus extends AbstractController
{
    use ComponentToolsTrait;
    use DefaultActionTrait;
    use ValidatableComponentTrait;

    #[LiveProp]
    public array $attendanceIds = [];

    #[LiveProp]
    public bool $stashed = false;

    #[LiveProp(writable: true, onUpdated: 'updatedStatus')]
    #[Assert\NotBlank]
    public string $status = '';

    #[LiveProp(writable: true)]
    public bool $notify = true;

    #[LiveProp(writable: true, onUpdated: 'updatedCommit')]
    public bool $commit = true;
    public ?string $notificationUuid = null;
    public ?string $confirm = null;

    public function __construct(private readonly ParticipantListFacade $participantList, private readonly EntityManagerInterface $entityManager, private readonly AttendanceRepository $attendanceRepository, private readonly AttendanceNotificationChecker $notificationChecker)
    {
    }

    public function mount(): void
    {
        if ($this->stashed) {
            $this->notify = false;
            $this->commit = false;
        }
    }

    #[ExposeInTemplate]
    public function isNotifiable(): bool
    {
        if (!$this->commit) {
            return false;
        }

        if ('' === $this->status) {
            return true;
        }

        return $this->notificationChecker->shouldNotify($this->status, true);
    }

    #[ExposeInTemplate]
    public function isParticipantNotifiable(): bool
    {
        return 0 === \count($this->nonNotifiableParticipants());
    }

    #[ExposeInTemplate]
    public function nonNotifiableParticipants(): array
    {
        $nonNotifiable = [];
        foreach ($this->attendances() as $attendance) {
            $participant = $attendance->getParticipant();
            if ($participant instanceof ParticipantInterface && !($participant->getEmail() || $participant->getMobile())) {
                $nonNotifiable[] = $participant;
            }
        }

        return $nonNotifiable;
    }

    public function updatedStatus(): void
    {
        if (!$this->isNotifiable()) {
            $this->notify = false;
        }
    }

    public function updatedCommit(): void
    {
        if (!$this->isNotifiable()) {
            $this->notify = false;
        }
    }

    #[ExposeInTemplate]
    public function attendances(): array
    {
        return $this->attendanceRepository->findBy(['id' => $this->attendanceIds]);
    }

    #[ExposeInTemplate]
    public function offer(): ?OfferInterface
    {
        $attendances = $this->attendances();

        return $attendances[0]?->getOffer();
    }

    #[LiveAction]
    public function submit(): void
    {
        if (!$this->isNotifiable()) {
            $this->notify = false;
        }

        $this->validate();

        $attendances = $this->attendances();

        $this->notificationUuid = (string) Uuid::v7();
        if ('confirmed' === $this->status) {
            $this->participantList->confirm($attendances, $this->notify, $this->commit, Uuid::fromString($this->notificationUuid));
            $this->confirm = 'Den Teilnehmer:innen wurde zugesagt.';
        } elseif ('withdrawn' === $this->status) {
            $this->participantList->reject($attendances, $this->notify, $this->commit, Uuid::fromString($this->notificationUuid));
            $this->confirm = 'Den Teilnehmer:innen wurde abgesagt.';
        }
    }
}
