<?php

namespace FiloBlu\Storelocator\Controller\Adminhtml\Stores;

use Exception;
use FiloBlu\Storelocator\Helper\Import;
use FiloBlu\Storelocator\Model\Stores\Image;
use FiloBlu\Storelocator\Model\StoresFactory;
use Magento\Backend\App\Action;
use Magento\Backend\Helper\Js;
use Magento\Directory\Model\RegionFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\File\Uploader;
use Magento\MediaStorage\Model\File\UploaderFactory;
use RuntimeException;

/**
 *
 */
class Save extends Action
{
    /**
     * @var \Magento\MediaStorage\Model\File\UploaderFactory
     */
    protected $uploaderFactory;
    /**
     * @var \FiloBlu\Storelocator\Model\Stores\Image
     */
    protected $imageModel;
    /**
     * @var \Magento\Backend\Helper\Js
     */
    protected $jsHelper;
    /**
     * @var \Magento\Directory\Model\RegionFactory
     */
    protected $regionFactory;
    /**
     * @var \FiloBlu\Storelocator\Model\StoresFactory
     */
    private $storesFactory;
    /**
     * @var \FiloBlu\Storelocator\Helper\Import
     */
    private $helperData;

    /**
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory
     * @param \FiloBlu\Storelocator\Model\Stores\Image $imageModel
     * @param \Magento\Backend\Helper\Js $jsHelper
     * @param \Magento\Directory\Model\RegionFactory $regionFactory
     * @param \FiloBlu\Storelocator\Model\StoresFactory $storesFactory
     * @param \FiloBlu\Storelocator\Helper\Import $helperData
     */
    public function __construct(
        Action\Context $context,
        UploaderFactory $uploaderFactory,
        Image $imageModel,
        Js $jsHelper,
        RegionFactory $regionFactory,
        StoresFactory $storesFactory,
        Import $helperData
    ) {
        $this->uploaderFactory = $uploaderFactory;
        $this->imageModel = $imageModel;
        $this->jsHelper = $jsHelper;
        $this->regionFactory = $regionFactory;
        parent::__construct($context);
        $this->storesFactory = $storesFactory;
        $this->helperData = $helperData;
    }

    /**
     * @return \Magento\Backend\Model\View\Result\Redirect
     * @throws \Magento\Framework\Exception\FileSystemException
     */
    public function execute()
    {
        $data = $this->getRequest()->getPostValue();
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();

        if ($data) {
            /** @var \FiloBlu\Storelocator\Model\Stores $model */
            $model = $this->storesFactory->create();

            $id = $this->getRequest()->getParam('id');

            if ($id) {
                $model->load($id);
            }
            $model->setData($data);

            if ($data['region']) {
                $model->setRegionId(null);
            }

            if (isset($data['region_id']) && $data['region_id']) {
                $region = $this->regionFactory->create()->load($data['region_id']);
                $regionName = $region->getDefaultName();
                $regionCode = $region->getCode();
                $model->setRegion($regionCode);
            }

            $imageName = $this->uploadFileAndGetName('image', $this->imageModel->getBaseDir(), $data);
            $model->setImage($imageName);
            $markerImageName = $this->uploadFileAndGetName('marker_image', $this->imageModel->getBaseDir(), $data);
            $model->setMarkerImage($markerImageName);

            if (!$model->getLatitude() || !$model->getLongitude()) {
                $address = $model->getData('street') . ' ' .
                    $model->getData('postcode') . ' ' .
                    $model->getData('city') . ' ' .
                    $model->getData('country');
                $geocodeData = $this->helperData->geocode($address);
                if ($geocodeData) {
                    $model->setLatitude($geocodeData[0]);
                    $model->setLongitude($geocodeData[1]);
                    $model->save();
                    $this->messageManager->addSuccess(
                        __('Geolocation data has been updated. Address found ' . $geocodeData[2])
                    );
                }
            }

            $tags = $this->getRequest()->getPost('tags', -1);

            if ($tags != -1) {
                $model->setTagsData($this->jsHelper->decodeGridSerializedInput($tags));
            }

            $images = $this->getRequest()->getPost('images', -1);

            if ($images != -1) {
                $model->setImagesData($this->jsHelper->decodeGridSerializedInput($images));
            }

            // Working Times
            $objWorkingTimes = [];
            for ($wt = 1; $wt <= 7; $wt++) {
                $dayStr = '';

                switch ($wt) {
                    case 1:
                        $dayStr = 'monday';
                        break;
                    case 2:
                        $dayStr = 'tuesday';
                        break;
                    case 3:
                        $dayStr = 'wednesday';
                        break;
                    case 4:
                        $dayStr = 'thursday';
                        break;
                    case 5:
                        $dayStr = 'friday';
                        break;
                    case 6:
                        $dayStr = 'saturday';
                        break;
                    case 7:
                        $dayStr = 'sunday';
                        break;

                    default:
                        break;
                }

                $objWorkingTimes[$dayStr . '_morning_time_from'] = '01/01/2000 ' . $data[$dayStr . '_morning_time_from'][0] . ':' . $data[$dayStr . '_morning_time_from'][1] . ':' . $data[$dayStr . '_morning_time_from'][2];
                $objWorkingTimes[$dayStr . '_morning_time_to'] = '01/01/2000 ' . $data[$dayStr . '_morning_time_to'][0] . ':' . $data[$dayStr . '_morning_time_to'][1] . ':' . $data[$dayStr . '_morning_time_to'][2];
                $objWorkingTimes['closed_' . $dayStr . '_morning'] = $data['closed_' . $dayStr . '_morning'];

                $objWorkingTimes[$dayStr . '_afternoon_time_from'] = '01/01/2000 ' . $data[$dayStr . '_afternoon_time_from'][0] . ':' . $data[$dayStr . '_afternoon_time_from'][1] . ':' . $data[$dayStr . '_afternoon_time_from'][2];
                $objWorkingTimes[$dayStr . '_afternoon_time_to'] = '01/01/2000 ' . $data[$dayStr . '_afternoon_time_to'][0] . ':' . $data[$dayStr . '_afternoon_time_to'][1] . ':' . $data[$dayStr . '_afternoon_time_to'][2];
                $objWorkingTimes['closed_' . $dayStr . '_afternoon'] = $data['closed_' . $dayStr . '_afternoon'];
            }

            $model->setObjWorkingTimes($objWorkingTimes);

            $this->_eventManager->dispatch(
                'filoblu_storelocator_store_prepare_save',
                [
                    'store' => $model,
                    'request' => $this->getRequest()
                ]
            );

            try {
                if(!$this->validateStoreData($model)) {
                    unset($data['image']);
                    $this->_getSession()->setFormData($data);
                    return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]);
                }

                $model->save();
                $this->messageManager->addSuccess(__('You saved this Store.'));
                $this->_getSession()->setFormData(false);
                if ($this->getRequest()->getParam('back')) {
                    return $resultRedirect->setPath('*/*/edit', ['id' => $model->getId(), '_current' => true]);
                }
                return $resultRedirect->setPath('*/*/');
            } catch (LocalizedException $e) {
                $this->messageManager->addError($e->getMessage());
            } catch (RuntimeException $e) {
                $this->messageManager->addError($e->getMessage());
            } catch (Exception $e) {
                $this->messageManager->addException($e, __('Something went wrong while saving the store.'));
            }

            $this->_getSession()->setFormData($data);
            return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]);
        }
        return $resultRedirect->setPath('*/*/');
    }

    public function uploadFileAndGetName($input, $destinationFolder, $data)
    {
        try {
            if (isset($data[$input]['delete'])) {
                return '';
            }

            $uploader = $this->uploaderFactory->create(['fileId' => $input]);
            $uploader->setAllowRenameFiles(true);
            $uploader->setFilesDispersion(true);
            $uploader->setAllowCreateFolders(true);
            $result = $uploader->save($destinationFolder);
            return $result['file'];
        } catch (Exception $e) {
            if ($e->getCode() != Uploader::TMP_NAME_EMPTY) {
                throw new Exception($e->getMessage());
            }

            if (isset($data[$input]['value'])) {
                return $data[$input]['value'];
            }
        }
        return '';
    }

    /**
     * {@inheritdoc}
     */
    protected function _isAllowed()
    {
        return $this->_authorization->isAllowed('FiloBlu_Storelocator::storelocator_save');
    }

    protected function validateStoreData($store) {
        if(!$this->helperData->validateFieldLength('title', $store->getTitle())) {
            $this->messageManager->addError('Title is too long (max '.$this->helperData->getConfig($this->helperData::TITLE_LENGTH_CONFIG_PATH, 0).' characters)');
            return false;
        }
        if(!$this->helperData->validateFieldLength('street', $store->getStreet())) {
            $this->messageManager->addError('Street is too long (max '.$this->helperData->getConfig($this->helperData::STREET_LENGTH_CONFIG_PATH, 0).' characters)');
            return false;
        }
        if(!$this->helperData->validateFieldLength('region_code', $store->getRegion())) {
            $this->messageManager->addError('State/Province is too long (max '.$this->helperData->getConfig($this->helperData::REGION_LENGTH_CONFIG_PATH, 0).' characters)');
            return false;
        }
        return true;
    }
}
