<?php

namespace FiloBlu\Storelocator\Model\ResourceModel;

use FiloBlu\Storelocator\Model\Store;
use FiloBlu\Storelocator\Model\WorkingTimesFactory;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Model\AbstractModel;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
use Magento\Framework\Model\ResourceModel\Db\Context;

/**
 *
 */
class Stores extends AbstractDb {

    /**
     * Event Manager
     *
     * @var ManagerInterface
     */
    protected $eventManager;

    /**
     * Tag relation model
     *
     * @var string
     */
    protected $storeTagTable;

    /**
     * Image relation model
     *
     * @var string
     */
    protected $storeImageTable;
	/**
	 * @var WorkingTimesFactory
	 */
	private $workingTimesFactory;

	/**
     * Initialize resource model
     *
     * @return void
     */
    protected function _construct() {
        $this->_init('filoblu_storelocator_stores', 'store_id');
    }

	/**
	 * @param ManagerInterface $eventManager
	 * @param Context $context
	 * @param WorkingTimesFactory $workingTimesFactory
	 */
    public function __construct(ManagerInterface $eventManager,
                                Context $context,
                                WorkingTimesFactory $workingTimesFactory) {

        parent::__construct($context);
        $this->storeTagTable = $this->getTable('filoblu_storelocator_store_tag');
        $this->storeImageTable = $this->getTable('filoblu_storelocator_store_image');
		$this->eventManager = $eventManager;
	    $this->workingTimesFactory = $workingTimesFactory;
    }

    /**
     * after save callback
     *
     * @param AbstractModel|\FiloBlu\Storelocator\Model\Stores $object
     * @return $this
     */
    protected function _afterSave(AbstractModel $object) {
        $this->saveTagRelation($object);
        $this->saveImageRelation($object);
        $this->saveWorkingTimesRelation($object);

        return parent::_afterSave($object);
    }

    /**
     * @param \FiloBlu\Storelocator\Model\Stores $store
     * @return void
     */
    protected function saveWorkingTimesRelation(\FiloBlu\Storelocator\Model\Stores $store) {
        if ($store->getObjWorkingTimes()) {
            $modelWT =  $this->workingTimesFactory->create();

            for ($wt = 1; $wt <= 7; $wt++) {

                $workingTimesMorning = $modelWT->loadByStoreIdDayPeriod($store->getStoreId(), $wt, 1);
                $workingTimesAfternoon = $modelWT->loadByStoreIdDayPeriod($store->getStoreId(), $wt, 2);

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

                // Morning
                $workingTimesMorning->setStoreId($store->getStoreId());
                $workingTimesMorning->setDay($wt);
                $workingTimesMorning->setPeriod(1);
                $workingTimesMorning->setFrom($store->getObjWorkingTimes($dayStr . '_morning_time_from'));
                $workingTimesMorning->setTo($store->getObjWorkingTimes($dayStr . '_morning_time_to'));
                $workingTimesMorning->setClosed($store->getObjWorkingTimes('closed_' . $dayStr . '_morning'));
                $workingTimesMorning->save();

                // Afternoon
                $workingTimesAfternoon->setStoreId($store->getStoreId());
                $workingTimesAfternoon->setDay($wt);
                $workingTimesAfternoon->setPeriod(2);
                $workingTimesAfternoon->setFrom($store->getObjWorkingTimes($dayStr . '_afternoon_time_from'));
                $workingTimesAfternoon->setTo($store->getObjWorkingTimes($dayStr . '_afternoon_time_to'));
                $workingTimesAfternoon->setClosed($store->getObjWorkingTimes('closed_' . $dayStr . '_afternoon'));
                $workingTimesAfternoon->save();
            }
        }
    }

    /**
     * @param \FiloBlu\Storelocator\Model\Stores $store
     * @return $this
     */
    protected function saveTagRelation(\FiloBlu\Storelocator\Model\Stores $store) {
        $store->setIsChangedTagList(false);
        $id = $store->getStoreId();
        $tags = $store->getTagsData();

        if ($tags === null) {
            return $this;
        }

        $oldTags = $store->getOldTags();

        $insert = array_diff($tags, $oldTags);
        $delete = array_diff($oldTags, $tags);

        $adapter = $this->getConnection();
        if (!empty($delete)) {
            $condition = ['tag_id IN(?)' => $delete, 'store_id=?' => $id];
            $adapter->delete($this->storeTagTable, $condition);
        }
        if (!empty($insert)) {
            $data = [];
            foreach ($insert as $tagId) {
                $data[] = [
                    'store_id' => (int) $id,
                    'tag_id' => (int) $tagId,
                ];
            }
            $adapter->insertMultiple($this->storeTagTable, $data);
        }

        if (!empty($insert) || !empty($delete)) {
            $store->setIsChangedTagList(true);
            $tagIds = array_merge($insert, $delete);
            $store->setAffectedTagIds($tagIds);
            $this->eventManager->dispatch(
                    'filoblu_storelocator_store_change_tags', [
                'store' => $store,
                'tag_ids_insert' => $insert,
                'tag_ids_delete' => $delete
                    ]
            );
        }

        return $this;
    }

    /**
     * @param \FiloBlu\Storelocator\Model\Stores $store
     * @return $this
     */
    protected function saveImageRelation(\FiloBlu\Storelocator\Model\Stores $store) {
        $store->setIsChangedImageList(false);
        $id = $store->getStoreId();
        $images = $store->getImagesData();
        if ($images === null) {
            return $this;
        }
        $oldImages = $store->getImagesPosition();
        $insert = array_diff_key($images, $oldImages);
        $delete = array_diff_key($oldImages, $images);
        $update = array_intersect_key($images, $oldImages);
        $_update = [];
        foreach ($update as $key => $settings) {
            if (isset($oldImages[$key]) && $oldImages[$key] != $settings['position']) {
                $_update[$key] = $settings;
            }
        }
        $update = $_update;
        $adapter = $this->getConnection();
        if (!empty($delete)) {
            $condition = ['image_id IN(?)' => array_keys($delete), 'store_id=?' => $id];
            $adapter->delete($this->storeImageTable, $condition);
        }
        if (!empty($insert)) {
            $data = [];
            foreach ($insert as $imageId => $position) {
                $data[] = [
                    'store_id' => (int) $id,
                    'image_id' => (int) $imageId,
                    'position' => (int) $position['position']
                ];
            }
            $adapter->insertMultiple($this->storeImageTable, $data);
        }
        if (!empty($update)) {
            foreach ($update as $imageId => $position) {
                $where = ['store_id = ?' => (int) $id, 'image_id = ?' => (int) $imageId];
                $bind = ['position' => (int) $position['position']];
                $adapter->update($this->storeImageTable, $bind, $where);
            }
        }
        if (!empty($insert) || !empty($delete)) {
//            $imageIds = array_unique(array_merge(array_keys($insert), array_keys($delete)));
            $this->eventManager->dispatch(
                    'filoblu_storelocator_store_change_images', [
                'store' => $store,
                'image_ids_insert' => $insert,
                'image_ids_delete' => $delete,
                'image_ids_update' => $update,
                    ]
            );
        }
        if (!empty($insert) || !empty($update) || !empty($delete)) {
            $store->setIsChangedImageList(true);
            $imageIds = array_keys($insert + $delete + $update);
            $store->setAffectedImageIds($imageIds);
        }

        return $this;
    }

	/**
	 * @param \FiloBlu\Storelocator\Model\Stores $store
	 * @return array
	 */
	public function getOldTags(\FiloBlu\Storelocator\Model\Stores $store) {
        $select = $this->getConnection()->select()->from(
                        $this->storeTagTable, ['tag_id']
                )
                ->where(
                'store_id = :store_id'
        );
        $bind = ['store_id' => (int) $store->getStoreId()];

		return $this->getConnection()->fetchCol($select, $bind);
    }

//    public function getOldImages(\FiloBlu\Storelocator\Model\Stores $store)
//    {
//        $select = $this->getConnection()->select()->from(
//            $this->storeImageTable,
//            ['image_id']
//        )
//            ->where(
//                'store_id = :store_id'
//            );
//        $bind = ['store_id' => (int)$store->getStoreId()];
//
//        $result = $this->getConnection()->fetchCol($select,$bind);
//
//        return $result;
//    }

    /**
     * @param \FiloBlu\Storelocator\Model\Stores $store
     * @return array
     */
    public function getImagesPosition(\FiloBlu\Storelocator\Model\Stores $store) {
        $select = $this->getConnection()->select()->from(
                        $this->storeImageTable, ['image_id', 'position']
                )
                ->where(
                'store_id = :store_id'
        );
        $bind = ['store_id' => (int) $store->getStoreId()];

        return $this->getConnection()->fetchPairs($select, $bind);
    }

	/**
	 * @param $storeId
	 * @return array
	 */
    public function getTagsIdByStore($storeId) {
        $select = $this->getConnection()->select()->from(
                        $this->storeTagTable, ['tag_id']
                )
                ->where(
                'store_id = :store_id'
        );
        $bind = ['store_id' => (int) $storeId];

	    return $this->getConnection()->fetchCol($select, $bind);
    }

	/**
	 * @param $storeId
	 * @return array
	 */
    public function getTagsNameByStore($storeId) {
        $select = $this->getConnection()->select()->from(
                        ['main_table' => $this->storeTagTable], ['']
                )
                ->where(
                'store_id = :store_id'
        );

        $select->join(
                ['related' => 'filoblu_storelocator_tags'], 'main_table.tag_id = related.tag_id', array('name')
        );

        $bind = ['store_id' => (int) $storeId];

	    return $this->getConnection()->fetchCol($select, $bind);
    }

	/**
	 * @param $storeId
	 * @return array
	 */
    public function getImagesStore($storeId) {
        $select = $this->getConnection()->select()->from(
                        ['main_table' => $this->storeImageTable], ['']
                )
                ->order(
                        'position ASC'
                )
                ->where(
                'store_id = :store_id'
        );

        $select->join(
                ['related' => 'filoblu_storelocator_images'], 'main_table.image_id = related.image_id', ['title', 'description', 'image']
        );

        $bind = ['store_id' => (int) $storeId];

	    return $this->getConnection()->fetchAll($select, $bind);
    }

}
