<?php

namespace FiloBlu\Storelocator\Helper;

use FiloBlu\Storelocator\Model\Import\Stores as ImportModel;
use FiloBlu\Storelocator\Model\Rma\Returntostore;
use FiloBlu\Storelocator\Model\StoresFactory;
use FiloBlu\Storelocator\Model\TagsFactory;
use FiloBlu\Storelocator\Model\WorkingTimesFactory;
use Magento\Directory\Model\RegionFactory;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\App\State;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Stdlib\DateTime\DateTime;
use Magento\Framework\Translate\Inline\StateInterface;
use Magento\Framework\View\Asset\Repository;
use Magento\Rma\Api\RmaRepositoryInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order\Address\Renderer;
use Magento\Store\Model\App\Emulation;
use Magento\Store\Model\StoreManagerInterface;

use function count;

/**
 *
 */
class Import extends Data
{
    protected $_storesFactory;
    protected $_tagsFactory;
    protected $_workingTimesFactory;
    protected $_regionFactory;

    const TITLE_LENGTH_CONFIG_PATH = 'filoblu_storelocator_section/store_fields_validation/store_title_length';
    const STREET_LENGTH_CONFIG_PATH = 'filoblu_storelocator_section/store_fields_validation/store_street_length';
    const REGION_LENGTH_CONFIG_PATH = 'filoblu_storelocator_section/store_fields_validation/store_region_length';

    /**
     * @param Context $context
     * @param StoreManagerInterface $storeManager
     * @param Repository $assetRepo
     * @param Returntostore $_returntostore
     * @param TagsFactory $_tagsFactory
     * @param OrderRepositoryInterface $orderRepository
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param RegionFactory $regionFactory
     * @param StoresFactory $storesFactory
     * @param StateInterface $inlineTranslation
     * @param \Magento\Payment\Helper\Data $paymentHelper
     * @param TransportBuilder $transportBuilder
     * @param Renderer $addressRenderer
     * @param \Magento\Rma\Helper\Data $rmaData
     * @param State $state
     * @param Emulation $appEmulation
     * @param TagsFactory $tagsFactory
     * @param WorkingTimesFactory $workingTimesFactory
     * @param \Magento\Framework\Stdlib\DateTime\DateTime $date
     * @param \Magento\Rma\Api\RmaRepositoryInterface $rmaRepository
     */
    public function __construct(
        Context $context,
        StoreManagerInterface $storeManager,
        Repository $assetRepo,
        Returntostore $_returntostore,
        TagsFactory $_tagsFactory,
        OrderRepositoryInterface $orderRepository,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        RegionFactory $regionFactory,
        StoresFactory $storesFactory,
        StateInterface $inlineTranslation,
        \Magento\Payment\Helper\Data $paymentHelper,
        TransportBuilder $transportBuilder,
        Renderer $addressRenderer,
        \Magento\Rma\Helper\Data $rmaData,
        State $state,
        Emulation $appEmulation,
        TagsFactory $tagsFactory,
        WorkingTimesFactory $workingTimesFactory,
        DateTime $date,
        RmaRepositoryInterface $rmaRepository

    ) {
        $this->_storesFactory = $storesFactory;
        $this->_tagsFactory = $tagsFactory;
        $this->_workingTimesFactory = $workingTimesFactory;
        $this->_regionFactory = $regionFactory;

        parent::__construct(
            $context,
            $storeManager,
            $assetRepo,
            $_returntostore,
            $_tagsFactory,
            $orderRepository,
            $searchCriteriaBuilder,
            $regionFactory,
            $storesFactory,
            $inlineTranslation,
            $paymentHelper,
            $transportBuilder,
            $addressRenderer,
            $rmaData,
            $state,
            $appEmulation,
            $date,
            $rmaRepository
        );
    }

    /**
     * @param $data
     * @return void
     * @throws \Exception
     */
    public function importDbData($data)
    {
        if ($data) {
            foreach ($data as $storeData) {
                if (!$storeData[ImportModel::LATITUDE] || !$storeData[ImportModel::LONGITUDE]) {
                    $address = (isset($storeData[ImportModel::STREET]) ? $storeData[ImportModel::STREET] . ' ' : '') .
                        (isset($storeData[ImportModel::POSTCODE]) ? $storeData[ImportModel::POSTCODE] . ' ' : '') .
                        (isset($storeData[ImportModel::CITY]) ? $storeData[ImportModel::CITY] . ' ' : '') .
                        (isset($storeData[ImportModel::COUNTRY]) ? $storeData[ImportModel::COUNTRY] . ' ' : '');
                    $geocodeData = $this->geocode($address);
                    if ($geocodeData) {
                        $storeData[ImportModel::LATITUDE] = $geocodeData[0];
                        $storeData[ImportModel::LONGITUDE] = $geocodeData[1];
                    }
                }

                if (!$storeData[ImportModel::ENABLED] && $storeData[ImportModel::ENABLED] != 0) {
                    $storeData[ImportModel::ENABLED] = 1;
                }

                if (!$storeData[ImportModel::IS_ENABLED_FOR_PICKUP_IN_STORE] && $storeData[ImportModel::IS_ENABLED_FOR_PICKUP_IN_STORE] != 0) {
                    $storeData[ImportModel::IS_ENABLED_FOR_PICKUP_IN_STORE] = 1;
                }

                if (!$storeData[ImportModel::IS_ENABLED_FOR_RETURN_IN_STORE] && $storeData[ImportModel::IS_ENABLED_FOR_RETURN_IN_STORE] != 0) {
                    $storeData[ImportModel::IS_ENABLED_FOR_RETURN_IN_STORE] = 1;
                }

                if (!$storeData[ImportModel::IS_ENABLED_SHOP_DETAILS] && $storeData[ImportModel::IS_ENABLED_SHOP_DETAILS] != 0) {
                    $storeData[ImportModel::IS_ENABLED_SHOP_DETAILS] = 1;
                }

                if (!$storeData[ImportModel::STORE_CODE] && $storeData[ImportModel::STORE_CODE] != '') {
                    $storeData[ImportModel::STORE_CODE] = $storeData[ImportModel::STORE_CODE];
                }

                if (!$storeData[ImportModel::STORE_IDS]) {
                    $storeData[ImportModel::STORE_IDS] = 0;
                }

                $storeData[ImportModel::EMAIL] = trim($storeData[ImportModel::EMAIL] ?? '');

                if (isset($storeData[ImportModel::REGION_CODE]) && $storeData[ImportModel::REGION_CODE] && $storeData[ImportModel::COUNTRY]) {
                    $region = $this->_regionFactory->create();
                    $regionId = $region->loadByCode(
                        $storeData[ImportModel::REGION_CODE],
                        $storeData[ImportModel::COUNTRY]
                    )->getId();
                    $storeData['region_id'] = $regionId;
                    $storeData[ImportModel::REGION] = $storeData[ImportModel::REGION_CODE];
                }

                $storeModel = $this->_storesFactory->create();
                $storeModel->addData($storeData);

                // Tags
                if (isset($storeData[ImportModel::TAGS])) {
                    $tagsArray = [];
                    $tags = explode(',', $storeData[ImportModel::TAGS]);

                    foreach ($tags as $tag) {
                        // check if exists
                        $modelTag = $this->_tagsFactory->create()->loadByTagName($tag);

                        if ($modelTag->getId()) {
                            $tagsArray[] = $modelTag->getId();
                        } else {
                            $modelTag->setName($tag);
                            $modelTag->setEnabled(1);
                            $tagsArray[] = $modelTag->save()->getId();
                        }
                    }

                    $storeModel->setTagsData($tagsArray);
                }

                // 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;
                    }

                    $currentDay = 'wt_' . $dayStr;

                    if (isset($storeData[$currentDay]) && !empty($storeData[$currentDay])) {
                        $storeData[$currentDay] = trim($storeData[$currentDay]);

                        if (strpos($storeData[$currentDay], ',') === false) {
                            // Continued timetable

                            $time = explode('-', $storeData[$currentDay]);

                            $objWorkingTimes[$dayStr . '_morning_time_from'] = '01/01/2000 ' . $time[0] . ':00';
                            $objWorkingTimes[$dayStr . '_morning_time_to'] = '01/01/2000 00:00:00';
                            $objWorkingTimes['closed_' . $dayStr . '_morning'] = 0;

                            $objWorkingTimes[$dayStr . '_afternoon_time_from'] = '01/01/2000 00:00:00';
                            $objWorkingTimes[$dayStr . '_afternoon_time_to'] = '01/01/2000 ' . $time[1] . ':00';
                            $objWorkingTimes['closed_' . $dayStr . '_afternoon'] = 0;
                        } else {
                            // Hours range
                            $morningTime = $this->getTimeMorning($storeData[$currentDay]);
                            $afternoonTime = $this->getTimeAfternoon($storeData[$currentDay]);

                            if ($morningTime) {
                                $time = explode('-', $morningTime);

                                $objWorkingTimes[$dayStr . '_morning_time_from'] = '01/01/2000 ' . $time[0] . ':00';
                                $objWorkingTimes[$dayStr . '_morning_time_to'] = '01/01/2000 ' . $time[1] . ':00';
                                $objWorkingTimes['closed_' . $dayStr . '_morning'] = 0;
                            } else {
                                $objWorkingTimes[$dayStr . '_morning_time_from'] = '01/01/2000 00:00:00';
                                $objWorkingTimes[$dayStr . '_morning_time_to'] = '01/01/2000 00:00:00';
                                $objWorkingTimes['closed_' . $dayStr . '_morning'] = 1;
                            }

                            if ($afternoonTime) {
                                $time = explode('-', $afternoonTime);

                                $objWorkingTimes[$dayStr . '_afternoon_time_from'] = '01/01/2000 ' . $time[0] . ':00';
                                $objWorkingTimes[$dayStr . '_afternoon_time_to'] = '01/01/2000 ' . $time[1] . ':00';
                                $objWorkingTimes['closed_' . $dayStr . '_afternoon'] = 0;
                            } else {
                                $objWorkingTimes[$dayStr . '_afternoon_time_from'] = '01/01/2000 00:00:00';
                                $objWorkingTimes[$dayStr . '_afternoon_time_to'] = '01/01/2000 00:00:00';
                                $objWorkingTimes['closed_' . $dayStr . '_afternoon'] = 1;
                            }
                        }
                    } else {
                        $objWorkingTimes[$dayStr . '_morning_time_from'] = '01/01/2000 00:00:00';
                        $objWorkingTimes[$dayStr . '_morning_time_to'] = '01/01/2000 00:00:00';
                        $objWorkingTimes['closed_' . $dayStr . '_morning'] = 0;

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

                $storeModel->setObjWorkingTimes($objWorkingTimes);
                $storeModel->save();
            }
        }
    }

    /**
     * @param $hours
     * @return false|string
     */
    private function getTimeMorning($hours)
    {
        $arrayHours = explode(',', $hours);

        if (count($arrayHours) > 2) {
            return false;
        }

        return $arrayHours[0] ?? false;
    }

    /**
     * @param $hours
     * @return false|string
     */
    private function getTimeAfternoon($hours)
    {
        $arrayHours = explode(',', $hours);

        if (count($arrayHours) > 2) {
            return false;
        }

        return $arrayHours[1] ?? false;
    }

    /**
     * @param $hours
     * @return bool
     */
    public function validateHours($hours)
    {
        if (!empty($hours)) {
            $hours = trim($hours);

            if (strpos($hours, ',') !== false) {
                // Hours range
                $morningTime = $this->getTimeMorning($hours);
                $afternoonTime = $this->getTimeAfternoon($hours);

                if (!$morningTime && !$afternoonTime) {
                    return false;
                }

                if ($morningTime) {
                    if (!$this->validateTimeRange($morningTime)) {
                        return false;
                    }
                }

                if ($afternoonTime) {
                    if (!$this->validateTimeRange($afternoonTime)) {
                        return false;
                    }
                }

                return true;
            }

// Check if continued timetable

            if (!$this->validateTimeRange($hours)) {
                return false;
            }

            return true;
        }

        return true;
    }

    /**
     * @param $timeRange
     * @return bool
     */
    private function validateTimeRange($timeRange)
    {
        $time = explode('-', $timeRange);

        if (isset($time[0])) {
            if (!$this->validateTimeRegEx($time[0])) {
                return false;
            }
        } else {
            return false;
        }

        if (isset($time[1])) {
            if (!$this->validateTimeRegEx($time[1])) {
                return false;
            }
        } else {
            return false;
        }

        return true;
    }

    /**
     * @param $time
     * @return false|int
     */
    private function validateTimeRegEx($time)
    {
        return preg_match('#^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$#', $time);
    }

    /**
     * @param $enabled
     * @return bool
     */
    public function validateEnabled($enabled)
    {
        return !($enabled != 0 && $enabled != 1);
    }

    /**
     * @param $storeIds
     * @return bool
     */
    public function validateStoreIds($storeIds)
    {
        $isValid = true;

        $storeIdsArray = explode(',', $storeIds);

        foreach ($storeIdsArray as $storeId) {
            if (!isset($this->_storeManager->getStores()[trim($storeId)])) {
                $isValid = false;
            }
        }

        return $isValid;
    }

    /**
     * @param $fieldName
     * @return mixed|null
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getStoreFieldMaxLength($fieldName)
    {
        switch ($fieldName) {
            case 'title':
                return $this->getConfig(self::TITLE_LENGTH_CONFIG_PATH);
            case 'street':
                return $this->getConfig(self::STREET_LENGTH_CONFIG_PATH);
            case 'region_code':
                return $this->getConfig(self::REGION_LENGTH_CONFIG_PATH);
            default:
                return null;
        }
    }

    /**
     * @param $fieldName
     * @param $fieldValue
     * @return bool
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function validateFieldLength($fieldName, $fieldValue)
    {
        $fieldLength = $this->getStoreFieldMaxLength($fieldName);
        if (!$fieldLength) {
            return true;
        }
        if (\is_array($fieldValue)) {
            $fieldValue = implode(' ', $fieldValue);
        }
        return \strlen($fieldValue) <= $fieldLength;
    }
}
