<?php
/**
 * Created by PhpStorm.
 * User: jderosa
 * Date: 30/10/19
 * Time: 20.04
 */

namespace FiloBlu\Rma\Helper;

use Exception;
use Magento\Customer\Api\Data\AttributeMetadataInterface;
use Magento\Eav\Model\AttributeRepository;
use Magento\Eav\Model\Config as EavConfig;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Model\Entity\Attribute\Source\Table;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Rma\Model\ResourceModel\Item\Form\Attribute\CollectionFactory as RmaFormAttributesCollectionFactory;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Config;
use Magento\Sales\Model\Order\Status;
use Magento\Sales\Model\Order\StatusFactory;
use Magento\Sales\Model\ResourceModel\Order\Status as StatusResource;
use Magento\Sales\Model\ResourceModel\Order\StatusFactory as StatusResourceFactory;
use Psr\Log\LoggerInterface;

/**
 *
 */
class InstallHelper
{
    const RMA_RESOLUTION_ATTRIBUTE_CODE = 'resolution';

    const REASON_OTHER_RMA_ATTRIBUTE_CODE = 'reason_other';

    const REASON_RMA_ATTRIBUTE_CODE = 'reason';

    const ATTRIBUTES_TO_SORT = ['reason', 'resolution', 'change_size', 'condition'];

    const BE_STANDARD_REASONS = ['BE Rientro Giacenza', 'BE Rottura di Stock', 'BE Annullamento Tecnico'];

    const ORDER_STATUS_WAITING_FORM_RMA_RECEIVING = 'waiting_for_rma_receiving';

    const ORDER_STATUS_WAITING_FORM_RMA_RECEIVING_LABEL = 'Waiting for RMA receiving';

    const STATUS_WAITING_FORM_RMA_RECEIVING_STATES = [Order::STATE_NEW, Order::STATE_PROCESSING];

    /**
     * @var StatusFactory
     */
    protected $statusFactory;

    /**
     * @var StatusResourceFactory
     */
    protected $statusResourceFactory;

    /**
     * @var Config
     */
    protected $orderStatus;

    /**
     * @var AttributeRepository
     */
    protected $attributeRepository;

    /**
     * @var EavConfig
     */
    protected $eavConfig;

    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * @var EavSetupFactory
     */
    protected $eavSetupFactory;

    /**
     * @var RmaFormAttributesCollectionFactory
     */
    protected $rmaFormAttributesCollectionFactory;

    /**
     * InstallHelper constructor.
     * @param StatusFactory $statusFactory
     * @param StatusResourceFactory $statusResourceFactory
     * @param Config $orderStatus
     * @param AttributeRepository $attributeRepository
     * @param EavConfig $eavConfig
     * @param LoggerInterface $logger
     * @param EavSetupFactory $eavSetupFactory
     * @param RmaFormAttributesCollectionFactory $rmaFormAttributesCollectionFactory
     */
    public function __construct(
        StatusFactory                      $statusFactory,
        StatusResourceFactory              $statusResourceFactory,
        Config                             $orderStatus,
        AttributeRepository                $attributeRepository,
        EavConfig                          $eavConfig,
        LoggerInterface                    $logger,
        EavSetupFactory                    $eavSetupFactory,
        RmaFormAttributesCollectionFactory $rmaFormAttributesCollectionFactory
    ) {
        $this->statusFactory = $statusFactory;
        $this->statusResourceFactory = $statusResourceFactory;
        $this->orderStatus = $orderStatus;
        $this->attributeRepository = $attributeRepository;
        $this->eavConfig = $eavConfig;
        $this->logger = $logger;
        $this->eavSetupFactory = $eavSetupFactory;
        $this->rmaFormAttributesCollectionFactory = $rmaFormAttributesCollectionFactory;
    }

    /**
     * Create new custom order status and assign it to the new custom order state
     *
     * @return void
     *
     * @throws Exception
     */
    public function addNewOrderStatus($setup)
    {
        if ($this->checkIfStateAndStatusExists(ChangeSizeAttributeHelper::ORDER_STATUS_CHANGESIZE_LABEL)) {
            $this->logger->debug('Skipping creation of new order status : already exists!');
            return;
        }

        try {
            /** @var Status $status */
            $status = $this->statusFactory->create(['setup' => $setup]);
            $status->setData([
                'status' => ChangeSizeAttributeHelper::ORDER_STATUS_CHANGESIZE_CODE,
                'label' => ChangeSizeAttributeHelper::ORDER_STATUS_CHANGESIZE_LABEL
            ]);
            /** @var StatusResource $statusResource */
            $statusResource = $this->statusResourceFactory->create(['setup' => $setup]);
            $statusResource->save($status);
            $status->assignState(Order::STATE_NEW, false, true);
        } catch (Exception $exception) {
            $this->logger->critical($exception->getMessage(), ['exception' => $exception]);
        }
    }

    /**
     * @return bool
     */
    protected function checkIfStateAndStatusExists($status)
    {
        $exists = false;
        $allStatus = $this->orderStatus->getStatuses();
        if (in_array($status, $allStatus)) {
            $exists = true;
        }
        return $exists;
    }

    /**
     * @param $setup
     * @return void
     */
    public function addNewReasonOption($setup)
    {
        try {
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
            $resolution = $this->attributeRepository->get(
                ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                self::RMA_RESOLUTION_ATTRIBUTE_CODE
            );
            $resolutionOptions = $resolution->getOptions();
            $exists = false;
            foreach ($resolutionOptions as $option) {
                if ($option->getLabel() == ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_LABEL) {
                    $exists = true;
                }
            }
            if (!$exists) {
                $resolutionAttributeId = $resolution->getAttributeId();
                $options = [
                    'values' => [
                        ChangeSizeAttributeHelper::RESOLUTION_CHANGE_SIZE_OPTION_CODE => ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_LABEL
                    ],
                    'attribute_id' => $resolutionAttributeId
                ];

                $eavSetup->addAttributeOption($options);
            }
        } catch (Exception $e) {
            $this->logger->critical($e->getMessage(), ['exception' => $e]);
        }
    }

    /**
     * @param $setup
     * @return void
     */
    public function addNewRmaItem($setup)
    {
        try {
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
            $rmaItemEntityTypeId = $this->eavConfig->getEntityType(
                ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE
            )->getEntityTypeId();
            $eavSetup->addAttribute($rmaItemEntityTypeId, ChangeSizeAttributeHelper::CHANGE_SIZE_RMA_ATTRIBUTE_CODE, [
                'label' => ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_LABEL,
                'input' => 'select',
                'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => true,
                'visible_on_front' => true,
                'backend_type' => 'int',
                'source' => Table::class
            ]);

            $changeSizeRmaAttribute = $this->attributeRepository->get(
                ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                ChangeSizeAttributeHelper::CHANGE_SIZE_RMA_ATTRIBUTE_CODE
            );

            $attribute = $this->eavConfig->getAttribute(
                ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                ChangeSizeAttributeHelper::CHANGE_SIZE_RMA_ATTRIBUTE_CODE
            );
            $attribute->setData('used_in_forms', ['default']);
            $attribute->save();
        } catch (Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * @param $setup
     * @return void
     * @throws LocalizedException
     * @throws NoSuchEntityException
     */
    public function hideReasonOther($setup)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        $rmaItemEntityTypeId = $this->eavConfig->getEntityType(
            ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE
        )->getEntityTypeId();
        $attributeId = $this->attributeRepository->get(
            ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
            self::REASON_OTHER_RMA_ATTRIBUTE_CODE
        )->getAttributeId();
        $eavSetup->updateAttribute($rmaItemEntityTypeId, $attributeId, [
            'is_visible' => 0
        ]);
    }

    /**
     * @param $setup
     * @return void
     */
    public function sortAttributes($setup)
    {
        try {
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
            $attributesToSort = $this->getAllRmaFormAttributes();
            $sortOrder = [];
            $attributeCodesToSort = [];
            foreach ($attributesToSort as $attribute) {
                $sortOrder [] = $attribute->getSortOrder();
                $attributeCodesToSort [] = $attribute->getAttributeCode();
            }

            array_multisort($sortOrder, SORT_ASC, SORT_NUMERIC);

            $i = 0;
            foreach (self::ATTRIBUTES_TO_SORT as $attribute) {
                $rmaItemEntityTypeId = $this->eavConfig->getEntityType(
                    ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE
                )->getEntityTypeId();
                $attributeId = $this->attributeRepository->get(
                    ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                    $attribute
                )->getAttributeId();
                $eavSetup->updateAttribute($rmaItemEntityTypeId, $attributeId, [
                    'sort_order' => $sortOrder[$i]
                ]);
                $i++;
            }

            $others = array_diff($attributeCodesToSort, self::ATTRIBUTES_TO_SORT);
            foreach ($others as $attribute) {
                $rmaItemEntityTypeId = $this->eavConfig->getEntityType(
                    ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE
                )->getEntityTypeId();
                $attributeId = $this->attributeRepository->get(
                    ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                    $attribute
                )->getAttributeId();
                $eavSetup->updateAttribute($rmaItemEntityTypeId, $attributeId, [
                    'sort_order' => $sortOrder[$i]
                ]);
                $i++;
            }
        } catch (Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * @return AttributeMetadataInterface[]
     */
    protected function getAllRmaFormAttributes()
    {
        return $this->rmaFormAttributesCollectionFactory->create()->getItems() ?? [];
    }

    /**
     * @param $setup
     */
    public function createBeReturnReasons($setup)
    {
        try {
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
            $reasons = $this->attributeRepository->get(
                ChangeSizeAttributeHelper::REASON_CHANGE_SIZE_ENTITY_CODE,
                self::REASON_RMA_ATTRIBUTE_CODE
            );
            $reasonsOptions = $reasons->getOptions();
            $exists = false;
            foreach (self::BE_STANDARD_REASONS as $beReason) {
                foreach ($reasonsOptions as $option) {
                    if ($option->getLabel() == $beReason) {
                        $exists = true;
                        break;
                    }
                }
                if (!$exists) {
                    $reasonAttributeId = $reasons->getAttributeId();
                    $options = [
                        'values' => [
                            str_replace(' ', '_', strtolower($beReason)) => $beReason
                        ],
                        'attribute_id' => $reasonAttributeId
                    ];

                    $eavSetup->addAttributeOption($options);
                }
            }
        } catch (Exception $e) {
            $this->logger->critical($e->getMessage());
        }
    }

    public function addWaitingFormRmaReceivingStatus($setup)
    {
        if ($status = $this->statusFactory->create()->load(self::ORDER_STATUS_WAITING_FORM_RMA_RECEIVING)) {
            $this->assignStatusToState($status);
            return;
        }

        /** @var StatusResource $statusResource */
        $statusResource = $this->statusResourceFactory->create(['setup' => $setup]);
        /** @var Status $status */
        $status = $this->statusFactory->create();
        $status->setData([
            'status' => self::ORDER_STATUS_WAITING_FORM_RMA_RECEIVING,
            'label' => self::ORDER_STATUS_WAITING_FORM_RMA_RECEIVING_LABEL,
        ]);
        $statusResource->save($status);

        $this->assignStatusToState($status);
    }

    protected function assignStatusToState($status)
    {
        foreach (self::STATUS_WAITING_FORM_RMA_RECEIVING_STATES as $state) {
            try {
                $status->assignState($state, false, false);
            } catch (AlreadyExistsException $exception) {
                continue;
            }
        }
    }

}
