<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Cart;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Order\CartType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Command\NotificationCommand;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Enum\PushLevel;
use CpCreation\VitiCore\Cart\CartService;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\CartItem;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Shop\CartQuantityProgressResolver;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveListener;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent('cart:CartForm', template: '@components/cart/CartForm.html.twig')]
class CartForm extends AbstractController
{
    use ComponentToolsTrait;
    use ComponentWithFormTrait;
    use DefaultActionTrait;

    #[LiveProp(writable: true, fieldName: 'cartModel')]
    public ?Cart $cart = null;

    public array $quantityProgressRules = [];

    public bool $shippingCountryRulePending = false;

    public function __construct(
        private readonly CartService $cartService,
        private readonly CartRepository $cartRepository,
        private readonly Security $security,
        private readonly MessageBusInterface $commandSimpleBus,
        private readonly TranslatorInterface $translator,
        private readonly CartQuantityProgressResolver $cartQuantityProgressResolver,
    ) {
    }

    public ?string $deleteItemId = null;

    protected function instantiateForm(): FormInterface
    {
        $this->cart = $this->cartService->getCart();
        $this->refreshQuantityProgress();

        return $this->createForm(CartType::class, $this->cart);
    }

    #[LiveListener('cartUpdated')]
    public function refreshForm(): void
    {
        $this->resetForm();
        $this->cart = $this->cartService->getCart();
        $this->refreshQuantityProgress();
    }

    #[LiveAction]
    public function deleteItem(#[LiveArg('id')] CartItem $item): void
    {
        $cart = $this->cartService->getCart();
        $cart->removeItem($item);
        $this->cartRepository->save($cart);
        $this->deleteItemId = $item->getId();
        if ($cart->getItems()->isEmpty()) {
            $this->cartService->removeCart();
        }
        $this->emitSelf('cartUpdated');
    }

    #[LiveAction]
    public function submitCart(): ?RedirectResponse
    {
        $this->refreshQuantityProgress();

        if ($this->hasInvalidQuantityRules()) {
            $this->notifyInvalidCartRules();
            $this->dispatchBrowserEvent('cart:scroll-to-rules');
            $this->emitSelf('cartUpdated');

            return null;
        }

        try {
            $this->submitForm();
            $this->cart = $this->cartService->hydrateCart($this->cart);
            $this->cartRepository->save($this->cart);

            return $this->redirectToRoute('shop_checkout');
        } catch (UnprocessableEntityHttpException $e) {
            if ($this->form->getErrors(true)->count() > 0) {
                $notification = new NotificationCommand(
                    message: $this->form->getErrors(true)->current()->getMessage(),
                    level: PushLevel::ERROR
                );
                $this->commandSimpleBus->dispatch($notification);
            }
            $this->emitSelf('cartUpdated');
        }

        return null;
    }

    #[LiveAction]
    public function updateItemQuantity(): void
    {
        try {
            $this->submitForm();
            $this->cart = $this->cartService->hydrateCart($this->cart);
            $this->cartRepository->save($this->cart);
            $this->refreshQuantityProgress();
            $this->refreshForm();
        } catch (UnprocessableEntityHttpException $e) {
            if ($this->form->getErrors(true)->count() > 0) {
                $notification = new NotificationCommand(
                    message: $this->form->getErrors(true)->current()->getMessage(),
                    level: PushLevel::ERROR
                );
                $this->commandSimpleBus->dispatch($notification);
            }
            $this->emitSelf('cartUpdated');
        }
    }

    private function refreshQuantityProgress(): void
    {
        if (!$this->cart instanceof Cart) {
            $this->quantityProgressRules = [];
            $this->shippingCountryRulePending = false;

            return;
        }

        $countryCode = $this->cart->getDeliveryAddress()?->getCountry();
        $this->shippingCountryRulePending = null === $countryCode || '' === $countryCode;
        $this->quantityProgressRules = $this->cartQuantityProgressResolver->resolve(
            $this->cart,
            $this->cart->getLocale(),
        );
    }

    private function hasInvalidQuantityRules(): bool
    {
        return [] !== array_filter(
            $this->quantityProgressRules,
            static fn (array|object $rule): bool => false === $rule->isComplete,
        );
    }

    private function notifyInvalidCartRules(): void
    {
        $this->commandSimpleBus->dispatch(new NotificationCommand(
            message: $this->translator->trans(
                'cart.progress.notification',
                [],
                null,
                $this->cart?->getLocale(),
            ),
            level: PushLevel::ERROR,
        ));
    }
}
