<?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\Offer;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\CoreBundle\Entity\Edition;
use Ferienpass\CoreBundle\Enum\OfferStatus;
use Ferienpass\CoreBundle\Enum\OfferTransition;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Workflow\WorkflowInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;

#[AsLiveComponent(template: '@FerienpassAdmin/components/Offer/BulkStatus.html.twig', route: 'live_component_admin')]
final class BulkStatus extends AbstractController
{
    use DefaultActionTrait;

    #[LiveProp]
    public ?Edition $edition = null;

    public string $message = '';

    #[LiveProp(writable: true)]
    public ?string $fromStatus = null;

    #[LiveProp(writable: true)]
    public ?string $transition = null;

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

    public bool $success = false;

    public function __construct(
        private readonly OfferRepositoryInterface $offerRepository,
        private readonly WorkflowInterface $offerWorkflow,
        private readonly EntityManagerInterface $entityManager
    ) {
    }

    public function updatedFromStatus(): void
    {
        $this->transition = null;
    }

    #[ExposeInTemplate]
    public function statuses(): array
    {
        return [
            OfferStatus::DRAFT,
            OfferStatus::FINALIZED,
            OfferStatus::REVIEWED,
            OfferStatus::PUBLISHED,
            OfferStatus::CANCELLED,
        ];
    }

    #[ExposeInTemplate]
    public function transitions(): array
    {
        if (!$this->fromStatus) {
            return [];
        }

        $allTransitions = $this->offerWorkflow->getDefinition()->getTransitions();
        $enabledTransitions = [];

        foreach ($allTransitions as $transition) {
            $froms = $transition->getFroms();
            if (empty($froms) || \in_array($this->fromStatus, $froms, true)) {
                $name = $transition->getName();

                if (str_starts_with($name, OfferTransition::TO_DRAFT)) {
                    $name = OfferTransition::TO_DRAFT;
                }

                $enabledTransitions[] = $name;
            }
        }

        $allowed = [
            OfferTransition::FINALIZE,
            OfferTransition::APPROVE,
            OfferTransition::PUBLISH,
            OfferTransition::TO_DRAFT,
            OfferTransition::UNAPPROVE,
            OfferTransition::UNPUBLISH,
            OfferTransition::CANCEL,
            OfferTransition::RELAUNCH,
        ];

        return array_values(array_intersect($allowed, array_unique($enabledTransitions)));
    }

    #[ExposeInTemplate]
    public function countAffected(): int
    {
        if (!$this->edition || !$this->fromStatus) {
            return 0;
        }

        return $this->offerRepository->countByEditionAndStatus($this->edition, $this->fromStatus);
    }

    #[ExposeInTemplate]
    public function appliedOffers(): array
    {
        if (empty($this->appliedOfferIds)) {
            return [];
        }

        return $this->offerRepository->findBy(['id' => $this->appliedOfferIds]);
    }

    #[LiveAction]
    public function apply(): void
    {
        if (!$this->edition || !$this->fromStatus || !$this->transition) {
            return;
        }

        $offers = $this->offerRepository->findByEditionAndStatus($this->edition, $this->fromStatus);

        $this->appliedOfferIds = [];
        foreach ($offers as $offer) {
            $transition = $this->transition;

            // Special handling for to_draft from reviewed
            if (OfferTransition::TO_DRAFT === $transition && !$this->offerWorkflow->can($offer, $transition)) {
                $transition = OfferTransition::TO_DRAFT.'_2';
            }

            if ($this->offerWorkflow->can($offer, $transition)) {
                $this->offerWorkflow->apply($offer, $transition);
                $this->appliedOfferIds[] = $offer->getId();
            }
        }

        $this->entityManager->flush();

        $this->success = true;

        if (($count = \count($this->appliedOfferIds)) > 0) {
            $this->message = \sprintf('%d Angebote erfolgreich aktualisiert.', $count);
        } else {
            $this->message = 'Keine Angebote aktualisiert.';
        }
    }
}
