<?php

namespace Oney\ThreeByFour\Gateway\Request;

use Magento\Checkout\Model\Session;
use Magento\Framework\Filter\FilterManager;
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Magento\Directory\Model\Country;
use Oney\ThreeByFour\Helper\Config;
use Oney\ThreeByFour\Logger\Logger;

class AddressDataBuilder implements BuilderInterface
{
    const MAX_LENGTH = 38;
    const PICKUP = 1;
    const RELAY_POINT = 2;

    /**
     * @var Country
     */
    protected $_country;
    /**
     * @var FilterManager
     */
    protected $_filterManager;
    /**
     * @var Session
     */
    protected $checkoutSession;
    /**
     * @var Config
     */
    protected $config;
    /**
     * @var Logger
     */
    protected $_logger;

    public function __construct(
        Country $country,
        FilterManager $filterManager,
        Session $checkoutSession,
        Config $config,
        Logger $logger
    )
    {
        $this->_filterManager = $filterManager;
        $this->_country = $country;
        $this->checkoutSession = $checkoutSession;
        $this->config = $config;
        $this->_logger = $logger;
    }

    public function build(array $buildSubject)
    {
        if (!isset($buildSubject['payment']) || !$buildSubject['payment'] instanceof PaymentDataObjectInterface)
        {
            throw new \InvalidArgumentException('Payment data object should be provided');
        }
        $payment = $buildSubject['payment'];
        $billingAddress = $payment->getOrder()->getBillingAddress();
        $shippingAddress = $payment->getOrder()->getShippingAddress();
        $carrierCode = $this->getCarrierCode();
        $shippingMode = $this->config->getCarrierConfig($carrierCode, 'deliverymodecode');

        $customerAddress = [
            "postal_code" => $billingAddress->getPostcode(),
            "municipality" => $billingAddress->getCity(),
            "country_code" => $this->_country->loadByCode($billingAddress->getCountryId())->getData('iso3_code'),
            "country_label" => $this->_country->loadByCode($billingAddress->getCountryId())->getName()
        ];
        $deliveryAddress = [
            "postal_code" => $shippingAddress->getPostcode(),
            "municipality" => $shippingAddress->getCity(),
            "country_code" => $this->_country->loadByCode($shippingAddress->getCountryId())->getData('iso3_code'),
            "country_label" => $this->_country->loadByCode($shippingAddress->getCountryId())->getName()
        ];
        $deliveryAddressString = '';
        $storeName = '';

        $this->_logger->info('[SUCCESS] [JSON] Shipping mode: ', [
            'shipping_mode' => $shippingMode,
            'carrier_code' => $carrierCode
        ]);

        switch ($shippingMode) {

            case self::PICKUP:
                $storeName = $this->config->getConfigValue('general/store_information/name') ?? "Pickup Store";
                $storeName .= ' -';
                $deliveryAddressString .= $storeName.$this->config->getConfigValue('general/store_information/street_line1');
                if ($this->config->getConfigValue('general/store_information/street_line2') !== null) {
                    $deliveryAddressString .= ' -'.$this->config->getConfigValue('general/store_information/street_line2');
                }
                $deliveryAddress = [
                    "postal_code" => $this->config->getConfigValue('general/store_information/postcode'),
                    "municipality" => $this->config->getConfigValue('general/store_information/city'),
                    "country_code" => $this->_country->loadByCode($this->config->getConfigValue('general/store_information/country_id'))->getData('iso3_code'),
                    "country_label" => $this->_country->loadByCode($this->config->getConfigValue('general/store_information/country_id'))->getName()
                ];
                break;
            case self::RELAY_POINT:
                $storeName = $shippingAddress->getCompany() ?? "Relay Point";
                $storeName .= ' - ';
                break;
        }

            $deliveryAddressString .= $storeName.$this->config->getConfigValue('general/store_information/street_line1');
            if ($this->config->getConfigValue('general/store_information/street_line2') !== null) {
                $deliveryAddressString .= ' - '.$this->config->getConfigValue('general/store_information/street_line2');
            }
        if ($shippingMode != self::PICKUP) {

            $deliveryAddressString .= $storeName.$shippingAddress->getStreetLine1();
            if ($shippingAddress->getStreetLine2() !== null) {
                $deliveryAddressString .= ' - '.$shippingAddress->getStreetLine2();
            }
        }
        $deliveryAddress = array_merge($this->cutString($deliveryAddressString, 38), $deliveryAddress);

        $customerAddress_string = $billingAddress->getStreetLine1();
        if ($billingAddress->getStreetLine2() !== null) $customerAddress_string .= $billingAddress->getStreetLine2();

        $customerAddress = array_merge($this->cutString($customerAddress_string, 38), $customerAddress);

        $response = [
            "customer" => [
                "customer_address" => $customerAddress
            ],
            "purchase" => [
                "delivery" => [
                    "delivery_address" => $deliveryAddress
                ]
            ]
        ];

        $this->_logger->info('[SUCCESS] [JSON] Create Address object (AddressDataBuilder): ', [
            'address' => $response
        ]);
        return $response;
    }

    protected function getCarrierCode()
    {
        $code = $this->checkoutSession->getQuote()->getShippingAddress()->getShippingMethod();
        return substr($code, 0, (int)(strlen($code) / 2));
    }

    protected function cutString($string, $length, $format = [])
    {
        if (strlen($string) > $length) {
            if (strlen($string) > $length && $string[$length] == ' ') {
                $pos = $length;
            } else {
                $pos = strrpos(substr($string, 0, $length), ' ');
            }
            $key = count($format)+1;
            $format['line'.$key] = trim(substr($string, 0, $pos));
            $string = substr($string, $pos+1);
            if (strlen($string) > 0) {
                $format = $this->cutString($string, $length, $format);
            }
        } else if (strlen($string) > 0) {
            $key = count($format)+1;
            $format['line'.$key] = trim(substr($string, 0));
        }

        return $format;
    }

}
