<?php

namespace FiloBlu\ActiveCampaign\Cron;

use Exception;
use FiloBlu\ConsentsManager\Api\ConsentSubscriptionRepositoryInterface;
use FiloBlu\ConsentsManager\Api\Data\ConsentSubscriptionInterface;
use FiloBlu\ActiveCampaign\Helper\ConsentsProfilingHelper;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Stdlib\DateTime\DateTime;
use Psr\Log\LoggerInterface;

class CheckConsentSubscriptions
{
    /**
     * @var ConsentSubscriptionRepositoryInterface
     */
    private $consentSubscriptionRepository;

    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var DateTime
     */
    private $dateTime;

    /**
     * @var ConsentsProfilingHelper
     */
    private $consentsProfilingHelper;

    /**
     * @var ManagerInterface
     */
    private $eventManager;

    /**
     * CheckConsentSubscriptions constructor.
     * @param ConsentSubscriptionRepositoryInterface $consentSubscriptionRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param LoggerInterface $logger
     * @param DateTime $dateTime
     * @param ConsentsProfilingHelper $consentsProfilingHelper
     * @param ManagerInterface $eventManager
     */
    public function __construct(
        ConsentSubscriptionRepositoryInterface $consentSubscriptionRepository,
        SearchCriteriaBuilder                  $searchCriteriaBuilder,
        LoggerInterface                        $logger,
        DateTime                               $dateTime,
        ConsentsProfilingHelper                $consentsProfilingHelper,
        ManagerInterface                       $eventManager
    ) {
        $this->consentSubscriptionRepository = $consentSubscriptionRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->logger = $logger;
        $this->dateTime = $dateTime;
        $this->consentsProfilingHelper = $consentsProfilingHelper;
        $this->eventManager = $eventManager;
    }

    /**
     * @return void
     */
    public function execute()
    {
        try {
            $this->checkAndUpdateConsents();
        } catch (Exception $e) {
            $this->logger->error('Error during check consent subscription cron execution: ' . $e->getMessage());
        }
    }

    /**
     * Check on subscription and update field if necessary
     * @throws Exception
     */
    public function checkAndUpdateConsents()
    {
        if (!$this->consentsProfilingHelper->isConsentsManagerEnabled()) {
            return;
        }

        $subscriptions = $this->getAcceptedSubscriptions();

        /** @var ConsentSubscriptionInterface $subscription */
        foreach ($subscriptions as $subscription) {
            if ($this->shouldRevokeSubscription($subscription)) {
                $subscription->setRevokedAt($this->dateTime->gmtDate());
                $this->consentSubscriptionRepository->save($subscription);

                // event dispatch after revoked_at filed updated
                $this->eventManager->dispatch(
                    'filoblu_consent_subscription_revoked',
                    ['subscription' => $subscription]
                );
            }
        }
    }

    /**
     * Get all accepted consent with revoked_at null.
     */
    public function getAcceptedSubscriptions(): array
    {
        $searchCriteria = $this->searchCriteriaBuilder
            ->addFilter('revoked_at', true, 'null')
            ->addFilter('accepted_at', true, 'notnull')
            ->create();

        $searchResults = $this->consentSubscriptionRepository->getList($searchCriteria);

        return $searchResults->getItems();
    }

    /**
     * Define if a subscription should be revoked
     *
     * @param $subscription
     * @return bool
     * @throws Exception
     */
    public function shouldRevokeSubscription($subscription): bool
    {
        $revokeAfterMonthsValue = $this->consentsProfilingHelper->getRevokeAfterMonthConfiguration();
        $acceptedAt = $subscription->getAcceptedAt();

        if (!$acceptedAt) {
            return false;
        }

        $acceptedDate = new \DateTime($acceptedAt);
        $currentDate = new \DateTime();
        $interval = $currentDate->diff($acceptedDate);
        $monthsPassed = ($interval->y * 12) + $interval->m;

        return $monthsPassed >= (int)$revokeAfterMonthsValue;
    }
}
