<?php

namespace Benhauer\Salesmanago\Controller\Adminhtml\Config;

use Magento\Framework\Message\ManagerInterface;
use \Psr\Log\LoggerInterface;

use \Magento\Backend\App\Action\Context;
use \Magento\Framework\View\Result\PageFactory;
use \Magento\Backend\Model\Auth\Session;
use \Magento\Newsletter\Model\Subscriber;
use \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory;
use \Magento\Newsletter\Model\ResourceModel\Subscriber\CollectionFactory as SubscriberCollectionFactory;
use \Magento\Sales\Model\ResourceModel\Order\CollectionFactory as OrderCollectionFactory;
use \Magento\Framework\Controller\Result\JsonFactory;

use \Benhauer\Salesmanago\Exception\SalesManagoException;
use \Benhauer\Salesmanago\Exception\UserAccessException;
use \Benhauer\Salesmanago\Helper\Config as ConfigHelper;
use \Benhauer\Salesmanago\Model\User as UserModel;
use \Benhauer\Salesmanago\Model\Export as ExportModel;

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

class ExportData extends \Magento\Backend\App\Action
{
    const
        ADVANCED = 'advanced',
        WITH_STATUS = 'exportWithStatus',
        CALENDAR = 'calendar',
        C_FROM = 'from',
        C_TO = 'to',
        EXP_PACKAGE_SIZE = 200;

    protected $factoryOrganizer;
    protected $model;
    protected $context;
    protected $storeId = 0;
    protected $scope = 'default';
    protected $messageManager;
    protected static $exportedOrderTypes = [
        'complete',
        'closed',
        'pending'
    ];

    protected $requestParams;

    public $advancedExport;
    public $exportTags;
    public $exportDateRange;
    public $subscriberFactory;
    public $exportModel;

    public function __construct(
        Context $context,
        UserModel $model,
        FactoryOrganizer $factoryOrganizer,
        ConfigHelper $config,

        JsonFactory $resultJsonFactory,
        PageFactory $pageFactory,
        Subscriber $subscriber,
        CustomerCollectionFactory $customerFactory,
        SubscriberCollectionFactory $subscriberFactory,
        OrderCollectionFactory $orderFactory,
        ExportModel $exportModel,
        LoggerInterface $logger
    ) {
        parent::__construct($context);
        $this->model = $model;
        $this->config = $config;
        $this->factoryOrganizer = $factoryOrganizer;
        $this->messageManager = $context->getMessageManager();

        $this->pageFactory = $pageFactory;
        $this->subscriber = $subscriber;
        $this->customerFactory = $customerFactory;
        $this->orderFactory = $orderFactory;
        $this->factoryOrganizer = $factoryOrganizer;
        $this->logger = $logger;
        $this->exportModel = $exportModel;
        $this->subscriberFactory = $subscriberFactory;
    }

    public function execute()
    {
        if ($loadByStoreCheck = $this->loadByStoreCheck()) {
            return $loadByStoreCheck;
        }

        $this->requestParams = $this->getRequest()->getParam('exportConfig');

        if ($this->requestParams) {
            $this->exportData($this->requestParams);
        }

        $this->renderView();
    }

    public function exportData($export) {
        if ($this->requestParams['contactsExport']) {
            $this->setContacts();
        }

        if ($this->requestParams['eventsExport']) {
            $this->setEvents();
        }
    }

    protected function loadByStoreCheck()
    {
        $this->storeId = $this->getRequest()->getParam('store');

        if ($this->storeId == null || $this->storeId == 0) {
            $this->storeId = 0;
            $this->scope = 'default';
        }

        if ($this->storeId != null) {
            $this->model
                ->setScopeId($this->storeId)
                ->setScope($this->scope);
        }

        if ($this->storeId && !$this->model->isPluginConfActive()) {
            return $this->redirectTo();
        }

        return false;
    }

    protected function redirectTo($redirectTo = 'index')
    {
        $store = '';
        if (!empty($this->storeId)) {
            $store = '/store/'.$this->storeId ;
        }
        return $this->_redirect('*/*/'.$redirectTo.$store);
    }

    protected function renderView(){
        $this->_view->loadLayout();
        $this->_view->renderLayout();
    }

    protected function setContacts()
    {
        try {
            $userAccount = $this->factoryOrganizer->getInst(
                FactoryOrganizer::USER_ACCOUNT_C,
                UserProvider::initSettingsUser(
                    $this->model
                ),
                $this->model
            );
            /**@todo change this
             * if(isset($this->requestParams[self::ADVANCED])) {
             *      $this->setAdvancedExport($this->requestParams[self::ADVANCED]);
             * }
             */
            if (isset($this->requestParams[self::WITH_STATUS])
                && !empty($this->requestParams[self::WITH_STATUS])
            ) {
                $this->exportModel->setContactOptStatus($this->requestParams[self::WITH_STATUS]);
            }

            $cExportedCustomers = $this->exportCustomers($userAccount);
            $cExportedSubscribersNoCustomers = $this->exportSubscribersNoCustomer($userAccount);

            $this->messageManager->addSuccess(__("Success") . ' Exported Customers: '.$cExportedCustomers.' Exported Subscribers: '. $cExportedSubscribersNoCustomers);
        } catch (UserAccessException $e) {
            $this->logger->critical($e->getUserMessage());
        } catch (SalesManagoException $e) {
            $this->logger->critical($e->getSalesManagoMessage());
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * Prapare & export packages of contacts from customers to SM
     * @param object $userAccount - form salesmanaga service
     * @return integer subscriber collection size;
     * @throw & @log UserAccessException, SalesManagoException, Exception
     */
    protected function exportCustomers($userAccount)
    {
        try{
            $CustomerCollection = $this->getCustomerCollection();
            $customerCollectionSize = $CustomerCollection->getSize();

            $loops = intval(ceil($customerCollectionSize / self::EXP_PACKAGE_SIZE));
            $CustomerCollection->setPageSize(self::EXP_PACKAGE_SIZE);

            for ($i = 1; $i <= $loops; $i++) {
                $CustomerCollection->setCurPage($i);
                $CustomerCollectionExportData = $this->exportModel
                    ->prepareContactsToExport(
                        $CustomerCollection,
                        $this->subscriber
                    );
                $userAccount->exportContacts($CustomerCollectionExportData);
            }

            return $customerCollectionSize;
        } catch (UserAccessException $e) {
            $this->logger->critical($e->getUserMessage());
        } catch (SalesManagoException $e) {
            $this->logger->critical($e->getSalesManagoMessage());
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * Prapare & export packages of contacts from subscribers to SM
     * @param object $userAccount - form salesmanaga service
     * @return integer subscriber collection size;
     * @throw & @log UserAccessException, SalesManagoException, Exception
     */
    protected function exportSubscribersNoCustomer($userAccount)
    {
        try{
            $SubscribersCollection = $this->getSubscribersNoCustomerCollection();
            $subscribersCollectionSize = $SubscribersCollection->getSize();

            $loops = ceil($subscribersCollectionSize / self::EXP_PACKAGE_SIZE);
            $SubscribersCollection->setPageSize(self::EXP_PACKAGE_SIZE);

            for ($i = 0; $i < $loops; $i++) {
                $SubscribersCollection->setCurPage($i);
                $SubscribersCollectionExportData = $this->exportModel->prepareContactsToExport(
                    $SubscribersCollection,
                    $this->subscriber
                );
                $userAccount->exportContacts($SubscribersCollectionExportData);
            }

            return $subscribersCollectionSize;
        } catch (UserAccessException $e) {
            $this->logger->critical($e->getUserMessage());
        } catch (SalesManagoException $e) {
            $this->logger->critical($e->getSalesManagoMessage());
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    protected function setEvents()
    {
        try {
            $userAccount = $this->factoryOrganizer->getInst(
                FactoryOrganizer::USER_ACCOUNT_C,
                UserProvider::initSettingsUser(
                    $this->model
                ),
                $this->model
            );

            if (isset($this->requestParams[self::ADVANCED])) {
                $this->setAdvancedExport($this->requestParams[self::ADVANCED]);
            }

            $collectSize = $this->getCountOrders();
            $collection = $this->getOrdersCollection();

            $loops = intval(ceil($collectSize / self::EXP_PACKAGE_SIZE));
            $collection->setPageSize(self::EXP_PACKAGE_SIZE);

            for ($i = 0; $i < $loops; $i++) {
                $collection->setCurPage($i);
                $orders = $collection->setOrder('entity_id', 'DESC');
                $package = $this->exportModel->prepareOrdersToExport($orders);
                $userAccount->exportContactExtEvents($package);
            }
            $this->messageManager->addSuccess(__("Success").' '.$collectSize. ' events was exported');
        } catch (UserAccessException $e) {
            $this->logger->critical($e->getUserMessage());
            $this->messageManager->addError($e->getUserMessage());
        } catch (SalesManagoException $e) {
            $this->logger->critical($e->getSalesManagoMessage());
            $this->messageManager->addError($e->getUserMessage());
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
            $this->messageManager->addError($e->getMessage());
        }
    }

    /**
     * Filter Order collection depends on $this->exportDateRange, $this->storeId
     * @return \Magento\Sales\Model\ResourceModel\Order\Collection $orderFactory
     */
    protected function getOrdersCollection()
    {
        try {
            $orderFactory = $this->orderFactory->create();

            if (isset($this->exportDateRange)) {
                $orderFactory->addFieldToFilter(
                    'created_at',
                    [
                        'from' => $this->exportDateRange['from'],
                        'to' => $this->exportDateRange['to'],
                        'date' => true
                    ]
                );
            }

            if ($this->storeId != 0) {
                $orderFactory->addFieldToFilter('store_id', ['eq' => $this->storeId]);
            }

            $orderFactory
                ->addFieldToFilter('status', ['in' => self::$exportedOrderTypes])
                ->addFieldToSelect(['*']);

            return $orderFactory;

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

    /**
     * @return int - size of Customer collection
     */
    protected function getCountOrders()
    {
        return $this->getOrdersCollection()->getSize();
    }

    protected function setAdvancedExport($param)
    {
        $this->advancedExport = $param['active'];

        if ($this->advancedExport
            && !empty($param['tag'])
        ) {
            $this->exportModel->setExportTags($param['tag']);
        }

        if ($this->advancedExport
            && !empty($param[self::CALENDAR][self::C_FROM])
            && !empty($param[self::CALENDAR][self::C_TO])
        ) {
            $this->exportDateRange = [
                'from' => $param[self::CALENDAR][self::C_FROM].' 00:00:01',
                'to'   => $param[self::CALENDAR][self::C_TO].' 23:59:59'
            ];
        }

        return $this;
    }

    /**
     * Filter Customer collection depends on $this->exportDateRange, $this->storeId
     * @return \Magento\Customer\Model\ResourceModel\Customer\Collection|\Magento\Framework\Data\Collection\AbstractDb $customerFactory
     */
    protected function getCustomerCollection()
    {
        try {
            $customerFactory = $this->customerFactory
                ->create()
                ->addFieldToSelect(array('*'));

            if ($this->storeId !== 0) {
                $customerFactory->addFieldToFilter('store_id', ['eq' => $this->storeId]);
            }

            if (isset($this->exportDateRange)) {
                $customerFactory
                    ->addFieldToFilter(
                        'created_at',
                        [
                            'from' => $this->exportDateRange[self::C_FROM],
                            'to' => $this->exportDateRange[self::C_TO]
                        ]
                    );
            }

            return $customerFactory;

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

    /**
     * Filter Subscriber collection depends on $this->exportDateRange, $this->storeId
     * @return \Magento\Newsletter\Model\ResourceModel\Subscriber\Collection $subscriberFactory - subscribers which is not a customer
     */
    protected function getSubscribersNoCustomerCollection()
    {
        try {
            $subscriberFactory = $this->subscriberFactory->create();

            $subscriberFactory
                ->addFieldToSelect(array('*'))
                ->addFieldToFilter('customer_id', array('eq' => '0'));/*get only subscribers which aren't customers*/

            if ($this->storeId !== 0) {
                $subscriberFactory->addFieldToFilter('store_id', ['eq' => $this->storeId]);
            }

            if (isset($this->exportDateRange)) {
                $subscriberFactory
                    ->addFieldToFilter(
                        'change_status_at',
                        [
                            'from' => $this->exportDateRange[self::C_FROM],
                            'to' => $this->exportDateRange[self::C_TO]
                        ]
                    );
            }
            return $subscriberFactory;
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }
}
