<?php

namespace Benhauer\Salesmanago\Observer;

use \Psr\Log\LoggerInterface;

use \Magento\Framework\Stdlib\DateTime\TimezoneInterface as MagentoDateTime;
use \Magento\Framework\Event\Observer;
use \Magento\Framework\Event\ObserverInterface;
use \Magento\Checkout\Model\Session;
use \Magento\Store\Api\Data\StoreInterface;
use \Magento\Framework\UrlInterface;
use \Magento\Newsletter\Model\Subscriber;
use \Magento\Customer\Api\CustomerRepositoryInterface;
use \Magento\Framework\Stdlib\CookieManagerInterface;
use \Magento\Store\Model\StoreManagerInterface;

use \SALESmanago\Provider\UserProvider;
use \SALESmanago\Factories\FactoryOrganizer;

use \Benhauer\Salesmanago\Model\Hooks as HooksModel;
use \Benhauer\Salesmanago\Model\Contact;
use \Benhauer\Salesmanago\Helper\Tagger;

use \Magento\Customer\Model\Session as CustomerSession;
use \Benhauer\Salesmanago\Observer\AbstractObserver as SalesmanagoAbstractObserver;

class NewsletterStatusModified extends SalesmanagoAbstractObserver
{
    public $CustomerSession;

    public function __construct(
        Session $session,
        StoreInterface $store,
        Subscriber $subscriber,
        HooksModel $model,
        CustomerRepositoryInterface $customerRepositoryInterface,
        CookieManagerInterface $cookieManager,
        MagentoDateTime $objDate,
        FactoryOrganizer $factoryOrganizer,
        Tagger $tagger,
        LoggerInterface $logger,
        CustomerSession $CustomerSession,
        Contact $modelContact,
        StoreManagerInterface $storeManager
    ) {
        parent::__construct(
             $session,
             $store,
             $subscriber,
             $model,
             $customerRepositoryInterface,
             $cookieManager,
             $objDate,
             $factoryOrganizer,
             $tagger,
             $logger,
             $modelContact,
             $storeManager
        );
        $this->CustomerSession = $CustomerSession;
    }

    public function hookAct(Observer $observer)
    {
        try {
            /**Status 4 is setted while double optin is active, this if prevent from multiply upsert*/
            if ($observer->getSubscriber()->getStatus() == 4
                && $this->model->getApiDoubleOptIn() != false
            ) {
                return true;
            }

            if ($this->session->getProgrammaticallyNewsletterStatus()) {
                $this->session->setProgrammaticallyNewsletterStatus(false);
                return true;
            }

            if (($this->session->getLastSubscribedEmail() == $observer->getSubscriber()->getEmail())
                && !$this->isSubscriberStatusChanged($observer->getSubscriber())
            ) {
                return true;
            }

            $customerId = $observer->getSubscriber()->getCustomerId();
            $connectSalesManago = $this->getConnectSalesManago();

            if ($customerId != 0) {
                $contact = $this->getCustomerById($customerId);
            } else {
                $contact['data'] = [
                    'email' => $observer->getSubscriber()->getSubscriberEmail()
                ];

                $contact['options'] = [
                    'forceOptIn' => $observer->getSubscriber()->isSubscribed(),
                    'forceOptOut' => !$observer->getSubscriber()->isSubscribed(),
                    'forcePhoneOptIn' => $observer->getSubscriber()->isSubscribed(),
                    'forcePhoneOptOut' => !$observer->getSubscriber()->isSubscribed(),
                    HooksModel::SYNC_RULE => $this->model->getSynchronizeRule(),
                    'createdOn' => method_exists($observer->getSubscriber(), 'getCreatedAt')
                        ? date("F j, Y, g:i a", $observer->getSubscriber()->getCreatedAt())
                        : date("F j, Y, g:i a", time())
                ];
            }

            $contact = $this->setContactApiDoubleOptIn($contact, $observer->getSubscriber());

            $reqSubscriptionConfirmation = false;
            $contact = $this->tagger
                ->setModel($this->model)
                ->setCheckOptInState(false)
                ->setTags($contact, Tagger::T_NEWSLETTER, $reqSubscriptionConfirmation);


            $this->upsertContact($contact, $connectSalesManago, self::UPSERT_FLAG_STATUS);
            $this->session->setLastSubscribedEmail($observer->getSubscriber()->getEmail());

        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * @param array $contact - with key data & options;
     * @param object $subscriber
     * @return array $contact
     * @throws \Exception
     */
    public function setContactApiDoubleOptIn($contact, $subscriber)
    {
        try {
            $apiDoubleOptin = $this->CustomerSession->getApiDoubleOptInData();
            $email = $contact['data']['email'];

            if (is_array($apiDoubleOptin)
                && array_key_exists($email, $apiDoubleOptin)
                && $apiDoubleOptin[$email]) {
                return $contact;
            }

            $apiDoubleOptinConf = $this->model->getApiDoubleOptIn();

            if ($apiDoubleOptinConf['useApiDoubleOptIn']
                && $this->isOptIn($contact)
            ) {
                if (!empty($apiDoubleOptin)) {
                    $apiDoubleOptin = array_merge($apiDoubleOptin, [$email => true]);
                } else {
                    $apiDoubleOptin = [$email => true];
                }

                $this->session->setProgrammaticallyNewsletterStatus(true);
                $subscriber->setStatus(Subscriber::STATUS_UNCONFIRMED)->save();

                $this->CustomerSession->setApiDoubleOptInData($apiDoubleOptin);
                $contact['options'] = array_merge($contact['options'], $this->model->getApiDoubleOptIn());
            }
            return $contact;
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    private function isSubscriberStatusChanged($subscriber)
    {
        try {
            $previousStatus = (int) $subscriber->getOrigData('subscriber_status');
            $currentStatus = (int) $subscriber->getStatus();

            if ($previousStatus != $currentStatus) {
                return true;
            }
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
        return false;
    }
}
