<?php

namespace FiloBlu\Flow\Model\Channel;

use Exception;
use FiloBlu\Flow\Block\Adminhtml\Channel\Edit\Tab\Config as TabConfig;
use FiloBlu\Flow\Helper\LoggerProvider;
use FiloBlu\Flow\Model\ChannelFactory;
use Monolog\Logger;

use RuntimeException;
use function count;
use function is_array;
use function is_string;

/**
 * Class Config
 * @package FiloBlu\Flow\Model\Channel
 */
class Config
{
    const COPY_TO_ITE_MODE_AUTO = 'auto';
    const COPY_TO_ITE_MODE_FROM_EAVS_FILE = 'from_eavs_file';
    const DEFAULT_KILL_AFTER_MINUTES = 20;
    /**
     * @var array
     */
    public $_mappedData = [];

    /**
     * @var Logger
     */
    protected $_logger;

    /**
     * @var ChannelFactory
     */
    protected $channelFactory;

    /**
     * Config constructor.
     * @param LoggerProvider $loggerProvider
     * @param ChannelFactory $channelFactory
     */
    public function __construct(
        LoggerProvider $loggerProvider,
        ChannelFactory $channelFactory
    ) {
        $this->_logger = $loggerProvider->getLogger();
        $this->channelFactory = $channelFactory;
    }

    /**
     * @param $name
     * @return $this
     * @throws Exception
     */
    public function load($name)
    {
        $channel = $this->channelFactory->create()->load($name, 'name');

        if (!$channel) {
            throw new RuntimeException(__METHOD__ . "Config $name - Model for channel data not exist for json map");
        }

        // TODO: really necessary?
        $json_content = str_replace(["\n", "\t", "\r"], '', (string)$channel->getData('data'));

        try {
            $mapped_config = json_decode($json_content, true);
            $this->_mappedData = $mapped_config;
            $this->_logger->info("Config {$name} - Loaded map json file");
        } catch (Exception $e) {
            throw new Exception("Config  {$name} - Fail to load map json file");
        }

        return $this;
    }

    /**
     * @return array
     */
    public function getConfigData()
    {
        return $this->_mappedData;
    }

    /**
     * @param $field
     * @return mixed|null
     */
    public function get($field)
    {
        return $this->_mappedData[$field] ?? null;
    }

    /**
     * @return array
     */
    public function getFields()
    {
        return array_keys($this->_mappedData);
    }

    /**
     * @param $data
     * @return bool
     */
    public function checkData($data)
    {
        return count($data) === count($this->_mappedData);
    }

    /**
     * @return bool
     */
    public function usesMap()
    {
        if (isset($this->_mappedData['use_map'])) {
            return (bool)$this->_mappedData['use_map'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function getProcessReservedStock()
    {
        if (isset($this->_mappedData['config']['process_reserved_stock'])) {
            return (bool)$this->_mappedData['config']['process_reserved_stock'];
        }

        return false;
    }

    /**
     * @return array
     */
    public function getProcessReservedStockStatuses()
    {
        if (isset($this->_mappedData['config']['process_reserved_stock_status']) && is_array(
            $this->_mappedData['config']['process_reserved_stock_status']
        )) {
            return $this->_mappedData['config']['process_reserved_stock_status'];
        }

        return [];
    }

    /**
     * @return bool
     */
    public function getDiscardNoManagedStock()
    {
        if (isset($this->_mappedData['config']['discard_no_managed'])) {
            return (bool)$this->_mappedData['config']['discard_no_managed'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function getNotSpecifiedSkuQtyToZero()
    {
        if (isset($this->_mappedData['config']['not_specified_sku_to_zero_qty'])) {
            return (bool)$this->_mappedData['config']['not_specified_sku_to_zero_qty'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function getIndexerStrategy()
    {
        return $this->_mappedData['config']['indexer_strategy'] ?? TabConfig::INDEXER_STRATEGY_FULL;
    }

    /**
     * @return bool
     */
    public function getPreorderDiscard()
    {
        if (isset($this->_mappedData['config']['preorder_discard'])) {
            return (bool)$this->_mappedData['config']['preorder_discard'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function stripWhiteSpaces()
    {
        if (isset($this->_mappedData['config']['strip_white_space'])) {
            return (bool)$this->_mappedData['config']['strip_white_space'];
        }

        return true;
    }

    /**
     * @return string
     */
    public function getImageMediaGallery()
    {
        return $this->_mappedData['config']['image_media_gallery'] ?? 'media_gallery';
    }

    /**
     * @return string|null
     */
    public function getPreorderAttributeCode()
    {
        return $this->_mappedData['config']['preorder_attribute_code'] ?? '';
    }

    /**
     * @return null|string
     */
    public function getPreorderAttributeValue()
    {
        return $this->_mappedData['config']['preorder_attribute_value'] ?? null;
    }

    /**
     * @return bool
     */
    public function getFixInventorySourceItems()
    {
        if (isset($this->_mappedData['config']['fix_inventory_source_item'])) {
            return (bool)$this->_mappedData['config']['fix_inventory_source_item'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function getAllowProcessZeroPrices()
    {
        if (isset($this->_mappedData['config']['allow_process_zero_prices'])) {
            return (bool)$this->_mappedData['config']['allow_process_zero_prices'];
        }

        return false;
    }

    /**
     * Check if a warning should be triggered (e.g., email sent) when a product with zero price is found.
     *
     * @return bool
     */
    public function shouldWarningOnZeroPrice(): bool
    {
        if (isset($this->_mappedData['config']['warning_email_for_zero_prices'])) {
            return (bool)$this->_mappedData['config']['warning_email_for_zero_prices'];
        }

        return false;
    }

    /**
     * Get the list of email addresses to alert when a zero price is detected.
     *
     * @return array
     */
    public function getEmailToAlertForZeroPrice(): array
    {
        if (isset($this->_mappedData['config']['email_to_alert_for_zero_prices'])) {
            $emails = $this->_mappedData['config']['email_to_alert_for_zero_prices'];
            if (is_string($emails)) {
                return array_filter(array_map('trim', explode(',', $emails)));
            }
            if (is_array($emails)) {
                return $emails;
            }
        }

        return [];
    }

    /**
     * @return bool
     */
    public function isRetryAllowed()
    {
        if (isset($this->_mappedData['config']['allow_retry'])) {
            return (bool)$this->_mappedData['config']['allow_retry'];
        }

        return false;
    }

    /**
     * @return int
     */
    public function getMaxRetryCount()
    {
        if (isset($this->_mappedData['config']['max_retry_count'])) {
            return (int)$this->_mappedData['config']['max_retry_count'];
        }

        return 0;
    }

    /**
     * @return bool
     */
    public function getCopyToIte()
    {
        if (isset($this->_mappedData['config']['copy_to_ite'])) {
            return (bool)$this->_mappedData['config']['copy_to_ite'];
        }

        return false;
    }

    /**
     * @return string|null
     */
    public function getIteChannelName()
    {
        return $this->_mappedData['config']['ite_channel_name'] ?? null;
    }

    /**
     * @return mixed|string
     */
    public function getCopyToIteMode()
    {
        if (isset($this->_mappedData['config']['copy_to_ite_mode'])) {
            $mode = $this->_mappedData['config']['copy_to_ite_mode'];

            if ($mode === self::COPY_TO_ITE_MODE_AUTO) {
                return self::COPY_TO_ITE_MODE_AUTO;
            }

            if ($mode === self::COPY_TO_ITE_MODE_FROM_EAVS_FILE) {
                if (!$this->getCopyToIteReplaceFrom() || !$this->getCopyToIteReplaceTo()) {
                    return self::COPY_TO_ITE_MODE_AUTO;
                }
            }


            return $mode;
        }

        return self::COPY_TO_ITE_MODE_AUTO;
    }

    /**
     * @return mixed|null
     */
    public function getCopyToIteReplaceFrom()
    {
        return $this->_mappedData['config']['copy_to_ite_replace_from'] ?? null;
    }

    /**
     * @return mixed|null
     */
    public function getCopyToIteReplaceTo()
    {
        return $this->_mappedData['config']['copy_to_ite_replace_to'] ?? null;
    }

    /**
     * @return bool|null
     */
    public function getDbTableName()
    {
        if (isset($this->_mappedData['config']['db_table_name'])) {
            return (bool)$this->_mappedData['config']['db_table_name'];
        }

        return null;
    }

    /**
     * @return bool
     */
    public function allowConcurrency()
    {
        if (isset($this->_mappedData['config']['concurrency'])) {
            return (bool)$this->_mappedData['config']['concurrency'];
        }

        return true;
    }

    /**
     * @return int
     */
    public function getKillAfter(): int
    {
        // Default to 20 minutes
        $killAfter = (int)($this->_mappedData['config']['kill_after'] ?? self::DEFAULT_KILL_AFTER_MINUTES);

        if ($killAfter <= 0) {
            return  self::DEFAULT_KILL_AFTER_MINUTES;
        }

        return $killAfter;
    }

    /**
     * @return bool
     */
    public function getAutomaticBundleDefaultOptionSet(): bool
    {
        if (isset($this->_mappedData['config']['automatic_bundle_default_option_set'])) {
            return (bool)$this->_mappedData['config']['automatic_bundle_default_option_set'];
        }

        return true;
    }

    /**
     * @return bool
     */
    public function generateUrlKeyOnParse():bool
    {
        if (isset($this->_mappedData['config']['generate_url_key_on_parse'])) {
            return (bool)$this->_mappedData['config']['generate_url_key_on_parse'];
        }

        return false;
    }

    /**
     * @return bool
     */
    public function simplePriceFromConfigurable(): bool {
        return $this->_mappedData['config']['simple_price_from_configurable'] ?? false;
    }
}
