<?php

namespace App\EventListener;

use App\Utils\OperationUtils;
use App\Utils\PaymentUtils;
use App\Utils\TAVCotisationUtils;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Payum\Core\Extension\Context;
use Payum\Core\Extension\ExtensionInterface;
use Payum\Core\Model\PaymentInterface;
use Payum\Core\Request\Generic;
use Payum\Core\Request\GetHumanStatus;
use Payum\Core\Request\GetStatusInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\SerializerInterface;

class PaymentStatusExtension implements ExtensionInterface
{
    private $em;
    private $eventDispatcher;
    private $serializer;
    private $userManager;
    private $operationUtils;
    private $tavCotisationUtils;
    private $container;
    private $paymentUtils;

    /**
     * PaymentStatusExtension constructor.
     *
     * @param EntityManagerInterface $em
     */
    public function __construct(
        EntityManagerInterface $em,
        EventDispatcherInterface $eventDispatcher,
        SerializerInterface $serializer,
        UserManagerInterface $userManager,
        OperationUtils $operationUtils,
        TAVCotisationUtils $tavCotisationUtils,
        ContainerInterface $container,
        PaymentUtils $paymentUtils
    ) {
        $this->em = $em;
        $this->eventDispatcher = $eventDispatcher;
        $this->serializer = $serializer;
        $this->userManager = $userManager;
        $this->operationUtils = $operationUtils;
        $this->tavCotisationUtils = $tavCotisationUtils;
        $this->container = $container;
        $this->paymentUtils = $paymentUtils;
    }

    /**
     * Fired after a payum 'execute' to detect payment status changes after a notification
     * {@inheritDoc}
     */
    public function onPostExecute(Context $context)
    {
        $request = $context->getRequest();
        if (false == $request instanceof Generic) {
            return;
        }
        if ($request instanceof GetStatusInterface) {
            return;
        }

        $payment = $request->getFirstModel();
        if (false == $payment instanceof PaymentInterface) {
            return;
        }

        try {
            $token = $request->getToken();
        } catch (\Exception $e) {
            return;
        }

        // Get current & new status
        $context->getGateway()->execute($status = new GetHumanStatus($payment));

        $current_payment_status = $payment->getStatus();
        $new_status = $status->getValue();

        /* WARNING : THIS PIECE OF CODE IS USING INAPPROPRIATE GetHumanStatus::STATUS_AUTHORIZED :
         *
         * This is (another) issue here with Payum.
         * current_payment_status will never match STATUS_AUTHORIZED
         * on the opposite, we have no chance to detect 'authorised' value here
         * because Payzen vads_trans_status is written 'authorised' and not 'authorized'
         *
         * @see comment above notifyRecurringPaymentAction for more Payum weird stuff
        */
        if (!in_array($current_payment_status, ['captured', 'authorised', GetHumanStatus::STATUS_CAPTURED, GetHumanStatus::STATUS_AUTHORIZED])) {
            if (in_array($new_status, ['captured', 'authorised', GetHumanStatus::STATUS_CAPTURED, GetHumanStatus::STATUS_AUTHORIZED]) ) {
                $this->paymentUtils->handlePayzenNotificationCore($payment);
                // Invalidate (delete) notify token after payment is captured
                $this->em->remove($token);
                $this->em->flush();
            }
        }

        //Update status
        // Update payment status with status received in payzen response
        $payment->setStatus($new_status);

        //Flush
        $this->em->persist($payment);
        $this->em->flush();
    }

    /**
     * {@inheritDoc}
     */
    public function onPreExecute(Context $context)
    {
    }

    /**
     * {@inheritDoc}
     */
    public function onExecute(Context $context)
    {
    }
}
