<?php

namespace Benhauer\Salesmanago\Controller\Newsletter;

use \Magento\Checkout\Model\Session;
use \Magento\Newsletter\Model\Subscriber;
use \Magento\Framework\Controller\Result\JsonFactory;

use \Benhauer\Salesmanago\Model\Hooks;
use \Benhauer\Salesmanago\Model\AbstractModel;

abstract class Callback extends \Magento\Framework\App\Action\Action
{
    public $pageFactory;
    public $helper;
    public $subscriber;
    public $model;
    public $rJsonFactory;

    const TEST_MAIL = 'callback.test@salesmanago.com';

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $pageFactory,
        JsonFactory $resultJsonFactory,
        Subscriber $subscriber,
        Hooks $model,
        Session $session
    ) {
        parent::__construct($context);
        $this->pageFactory  = $pageFactory;
        $this->subscriber   = $subscriber;
        $this->model        = $model;
        $this->rJsonFactory = $resultJsonFactory->create();
        $this->session      = $session;
    }

    abstract public function execute();

    /**
     * Set contact status to subscribed;
    */
    public function optIn()
    {
        $params = $this->getRequest()->getParams();

        if ($this->isItTestCallback($params)) {
            return $this->response('optIn', true);
        }

        if (!$this->parametersChecker($params)) {
            return $this->response('', false, 'Does email exist?');
        }

        $checkSubscriber = $this->subscriber->loadByEmail($params['email']);

        if (in_array($checkSubscriber->getStatus(),
            [
                Subscriber::STATUS_NOT_ACTIVE,
                Subscriber::STATUS_UNCONFIRMED,
                Subscriber::STATUS_UNSUBSCRIBED
            ])
        ) {
            $this->session->setProgrammaticallyNewsletterStatus(true);
            $checkSubscriber->setStatus(Subscriber::STATUS_SUBSCRIBED)->save();
            return $this->response('optIn', true);
        }

        $this->_redirect('/');
    }

    /**
     * Set contact status to unsubscribed
    */
    public function optOut()
    {
        $params = $this->getRequest()->getParams();

        if ($this->isItTestCallback($params)) {
            return $this->response('optOut', true);
        }

        if (!$this->parametersChecker($params)) {
            return $this->response('', false, 'Does email exist?');
        }

        $checkSubscriber = $this->subscriber->loadByEmail($params['email']);

        if ($checkSubscriber->isSubscribed() || $checkSubscriber->getStatus() == 4 ) {
            $this->session->setProgrammaticallyNewsletterStatus(true);
            $checkSubscriber->unsubscribe();

            return $this->response('optOut', true);
        }

        $this->_redirect('/');
    }

    /**
     * Check if request is valid
     * @param array  - request
     * @return boolean
    */
    public function parametersChecker($params)
    {
        $clientsIds = $this->model->getClientsIds();

        if (!isset($params['email']) && empty($params['email'])) {
            return false;
        }

        if (!isset($params['key']) || empty($params['email'])) {
            return false;
        }

        $clientId = $this->model->getClientId();

        if (empty($clientId) && empty($clientsIds)) {
            return false;
        }

        if (count($clientsIds) != 1 || !empty($clientsIds)) {
            foreach ($clientsIds as $mClientId) {
                $localSha = sha1($params['email'] . $mClientId);
                if ($localSha == $params['key']) {
                    return true;
                }
            }
        }

        $localSha = sha1($params['email'] . $clientId);

        if ($localSha != $params['key']) {
            return false;
        }

        return true;
    }

    /**
     * Check if client send test callback
     * @param array  - request
     * @return boolean
    */
    public function isItTestCallback($params)
    {
        if ($params['email'] == self::TEST_MAIL
            && $this->parametersChecker($params)
        ) {
            return true;
        }

        return false;
    }

    /**
     * Return $this->rJsonFactory->data
     * @param string $inOut = 'optIn' || 'optOut'
     * @param success boolean
     * @param mixed $info - (string || null)
    */
    public function response($inOut, $success = false, $info = null)
    {
        return $this->rJsonFactory->setData(
            [
                'success' => $success,
                'message' => ($success) ? __("Contact is {$inOut}") : $info
            ]
        );
    }
}
