<?php

namespace Oney\ThreeByFour\Plugin\Config\Model\Config\Structure;

use Magento\Config\Model\Config\Source\Enabledisable;
use Magento\Config\Model\Config\Structure\Data;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Language\Dictionary;
use Magento\Framework\Locale\Resolver;
use Magento\Framework\Module\Manager;
use Magento\Framework\TranslateInterface;
use Magento\Paypal\Model\Config\StructurePlugin;
use Magento\Store\Model\StoreManagerInterface;
use Oney\ThreeByFour\Api\Marketing\BusinessTransactionsInterface;
use Oney\ThreeByFour\Helper\Config;
use Oney\ThreeByFour\Logger\Logger;
use Magento\Shipping\Model\Config as CarrierConfig;
use Oney\ThreeByFour\Model\Config\Source;

/**
 * Config Structure Data Plugin
 * 
 * Plugin for Magento config structure data.
 * Dynamically builds ThreeByFour payment method configuration structure.
 * 
 * @package Oney\ThreeByFour\Plugin\Config\Model\Config\Structure
 * @version 1.0.0
 * @author Oney
 * @since 1.0.0
 */
class DataPlugin
{
    /**
     * Payment section path
     * 
     * @const string
     * @version 1.0.0
     */
    const PATH = "payment/oney_section/oney_payments";

    /**
     * Delivery mode code configuration key
     * 
     * @const string
     * @version 1.0.0
     */
    const DELIVERY_MODE_CODE = "deliverymodecode";
    
    /**
     * Express delivery flag configuration key
     * 
     * @const string
     * @version 1.0.0
     */
    const EXPRESS_DELIVERY_FLAG = "expressdeliveryflag";

    /**
     * Carrier configuration keys
     * 
     * @const array
     * @version 1.0.0
     */
    const CARRIER_CONFIGS = [
        self::DELIVERY_MODE_CODE,
        self::EXPRESS_DELIVERY_FLAG
    ];

    /**
     * Country-specific admin groups mapping.
     * Add future country groups here (PT, RO, ...).
     *
     * @const array
     */
    const COUNTRY_SPECIFIC_GROUPS = [
        'FR' => ['oney_fr_speficifics']
    ];
    
    /**
     * Logger instance
     * 
     * @var Logger
     * @version 1.0.0
     */
    protected $_logger;
    
    /**
     * Business transactions service
     * 
     * @var BusinessTransactionsInterface
     * @version 1.0.0
     */
    protected $_businessTransactions;
    
    /**
     * Configuration helper
     * 
     * @var Config
     * @version 1.0.0
     */
    protected $_config;
    
    /**
     * Carrier configuration
     * 
     * @var CarrierConfig
     * @version 1.0.0
     */
    protected $_carrierConfig;
    
    /**
     * Module manager
     * 
     * @var Manager
     * @version 1.0.0
     */
    protected $moduleManager;
    
    /**
     * Locale resolver
     * 
     * @var Resolver
     * @version 1.0.0
     */
    protected $resolver;
    
    /**
     * Language dictionary
     * 
     * @var Dictionary
     * @version 1.0.0
     */
    protected $dictionary;
    
    /**
     * Translation interface
     * 
     * @var TranslateInterface
     * @version 1.0.0
     */
    protected $translate;

    /**
     * @var RequestInterface
     */
    private $request;

    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    
    /**
     * ThreeByFour method structure cache
     * 
     * @var array
     * @version 1.0.0
     */
    private $threeByFourMethodStructure = [];

    /**
     * Constructor
     * 
     * @param Logger $logger Logger instance
     * @param BusinessTransactionsInterface $businessTransactions Business transactions service
     * @param Config $config Configuration helper
     * @param CarrierConfig $carrierConfig Carrier configuration
     * @param Manager $moduleManager Module manager
     * @param Resolver $resolver Locale resolver
     * @param Dictionary $dictionary Language dictionary
     * @param TranslateInterface $translate Translation interface
     * @version 1.0.0
     */
    public function __construct(
        Logger $logger,
        BusinessTransactionsInterface $businessTransactions,
        Config $config,
        CarrierConfig $carrierConfig,
        Manager $moduleManager,
        Resolver $resolver,
        Dictionary $dictionary,
        TranslateInterface $translate,
        RequestInterface $request,
        StoreManagerInterface $storeManager
    ) {
        $this->_config = $config;
        $this->_logger = $logger;
        $this->_carrierConfig = $carrierConfig;
        $this->_businessTransactions = $businessTransactions;
        $this->moduleManager = $moduleManager;
        $this->resolver = $resolver;
        $this->dictionary = $dictionary;
        $this->translate = $translate->loadData();
        $this->request = $request;
        $this->storeManager = $storeManager;
    }

    /**
     * After get config data
     * 
     * Modifies config structure data to include ThreeByFour payment methods.
     * 
     * @param Data $subject Config structure data
     * @param mixed $return Original return value
     * @return mixed Modified config structure
     * @version 1.0.0
     */
    public function afterGet(Data $subject, $return)
    {
        if (isset($return['sections'])) {
            $this->filterCountrySpecificGroups($return['sections']);
            $paymentSection = [];
            if ($this->moduleManager->isEnabled("Magento_Paypal")) {
                foreach (StructurePlugin::getPaypalConfigCountries() as $country) {
                    if(!$this->_config->isLegalEnabled()) {
                        unset($return['sections'][$country]['children']['oney_section']['children']['oney_legal']);
                    }
                    $paymentSection[$country] = [
                        'children' => [
                            "oney_section" => [
                                "children" => [
                                    "oney_payments" => [
                                        "children" => $this->buildThreeByFourMethodStructure()
                                    ]
                                ]
                            ]
                        ]
                    ];
                }
                $paymentSection["payment_other"] = [
                    'children' => [
                        "oney_section" => [
                            "children" => [
                                "oney_payments" => [
                                    "children" => $this->buildThreeByFourMethodStructure()
                                ]
                            ]
                        ]
                    ]
                ];
            }
            $paymentSection["payment"] = [
                'children' => [
                    "oney_section" => [
                        "children" => [
                            "oney_payments" => [
                                "children" => $this->buildThreeByFourMethodStructure()
                            ]
                        ]
                    ]
                ]
            ];

            $sections['sections'] = array_merge($paymentSection, [
                'carriers' => [
                    'children' => isset($return['sections']['carriers']['children']) ? $this->buildCarrierStructure($return['sections']['carriers']['children']) : []
                ]
            ]);
            $return = array_merge_recursive($return, $sections);
        }
        return $return;
    }

    private function filterCountrySpecificGroups(array &$sections): void
    {
        $countryCode = $this->getCurrentScopeCountryCode();
        $allowedGroups = $this->getAllowedCountrySpecificGroups($countryCode);
        $allSpecificGroups = $this->getAllCountrySpecificGroups();

        foreach ($sections as &$section) {
            if (!isset($section['children']['oney_section']['children'])) {
                continue;
            }
            foreach ($allSpecificGroups as $groupId) {
                if (!in_array($groupId, $allowedGroups, true)) {
                    unset($section['children']['oney_section']['children'][$groupId]);
                }
            }
        }
    }

    private function getAllowedCountrySpecificGroups(string $countryCode): array
    {
        return self::COUNTRY_SPECIFIC_GROUPS[$countryCode] ?? [];
    }

    private function getAllCountrySpecificGroups(): array
    {
        $allGroups = [];
        foreach (self::COUNTRY_SPECIFIC_GROUPS as $groups) {
            foreach ($groups as $groupId) {
                $allGroups[] = $groupId;
            }
        }
        return array_values(array_unique($allGroups));
    }

    /**
     * @return string
     */
    private function getCurrentScopeCountryCode(): string
    {
        return strtoupper((string)$this->_config->getConfigValue('general/country/default', $this->resolveStoreIdFromScope()));
    }

    /**
     * @return int|null
     */
    private function resolveStoreIdFromScope(): ?int
    {
        $storeScope = $this->request->getParam('store');
        if (!empty($storeScope)) {
            try {
                return (int)$this->storeManager->getStore($storeScope)->getId();
            } catch (\Exception $e) {
                return null;
            }
        }

        $websiteScope = $this->request->getParam('website');
        if (!empty($websiteScope)) {
            try {
                $website = $this->storeManager->getWebsite($websiteScope);
                $defaultStore = $website->getDefaultStore();
                return $defaultStore ? (int)$defaultStore->getId() : null;
            } catch (\Exception $e) {
                return null;
            }
        }

        return null;
    }

    /**
     * Build ThreeByFour method structure
     * 
     * Builds configuration structure for ThreeByFour payment methods.
     * 
     * @return array Method structure configuration
     * @version 1.0.0
     */
    protected function buildThreeByFourMethodStructure(): array
    {
        if (empty($this->threeByFourMethodStructure)) {
            $comment_without_fee = "";
            foreach ($this->_businessTransactions->getBusinessTransactions() as $businessTransaction) {
                if($businessTransaction['without_fee']) {
                    $comment_without_fee = " - " . $this->translate('Without fees');
                }
                else {
                    $comment_without_fee = " - " . $this->translate('With fees');
                }
                $this->threeByFourMethodStructure[$businessTransaction['code']] = [
                    "id" => $businessTransaction['code'],
                    "translate" => "label comment",
                    "sortOrder" => "0",
                    "type" => "select",
                    "showInDefault" => "1",
                    "showInWebsite" => "1",
                    "showInStore" => "1",
                    "comment" => $this->translate("Customer's cart eligible amounts from %1 to %2",
                        [$businessTransaction['min_order_total'], $businessTransaction['max_order_total']]) . $comment_without_fee,
                    "label" => $businessTransaction['title'],
                    "config_path" => "payment/oney_section/" . $businessTransaction['code'],
                    "source_model" => Enabledisable::class,
                    "path" => self::PATH,
                    "_elementType" => "field"
                ];
            }
        }
        return $this->threeByFourMethodStructure;
    }

    /**
     * Build carrier structure
     * 
     * Builds carrier configuration structure with Oney-specific fields.
     * 
     * @param array $existingCarriers Existing carrier configurations
     * @return array Modified carrier structure
     * @version 1.0.0
     */
    protected function buildCarrierStructure(array $existingCarriers): array
    {
        $response = [];
        foreach ($this->_carrierConfig->getAllCarriers() as $carrier) {
            $code = $carrier->getCarrierCode();
            if (isset($existingCarriers[$code])) {
                foreach (self::CARRIER_CONFIGS as $configCode) {
                    $response[$code]['children'][$configCode] = $this->generateFieldCarrier($code, $configCode);
                }
            }
        }
        return $response;
    }

    /**
     * Generate field carrier
     * 
     * Generates carrier field configuration for specific carrier and config code.
     * 
     * @param string $carrierCode Carrier code
     * @param string $carrierConfigCode Carrier configuration code
     * @return array Field configuration
     * @version 1.0.0
     */
    protected function generateFieldCarrier(string $carrierCode, string $carrierConfigCode): array
    {
        $field = [
            "id" => $carrierConfigCode,
            "translate" => "label",
            "type" => "select",
            "showInDefault" => "1",
            "showInWebsite" => "1",
            "showInStore" => "1",
            "sortOrder" => "100",
            "_elementType" => "field",
            "path" => "carriers/" . $carrierCode

        ];
        switch ($carrierConfigCode) {
            case self::DELIVERY_MODE_CODE:
                $field["source_model"] = Source\DeliveryModeCode::class;
                $field["label"] = Source\DeliveryModeCode::LABEL;
                break;
            case self::EXPRESS_DELIVERY_FLAG:
                $field["source_model"] = Source\ExpressDeliveryFlag::class;
                $field["label"] = Source\ExpressDeliveryFlag::LABEL;
                break;
        }
        return $field;
    }

    /**
     * Translate text
     * 
     * Translates text with placeholders using translation data.
     * 
     * @param string $text Text to translate
     * @param array $arguments Translation arguments
     * @return string Translated text
     * @version 1.0.0
     */
    private function translate(string $text, array $arguments = []): string {
        try{
            $translate = $this->translate->getData()[$text];
        }catch (\Exception $e) {
            $translate = $text;
        }
        $placeHolder = [];
        foreach ($arguments as $key => $argument) {
            $placeHolder['%' . (is_int($key) ? (string)($key + 1) : $key)] = $argument;
        }
        return strtr($translate, $placeHolder);
    }
}
