<?php

namespace uafrica\Customshipping\Model\Carrier;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\DataObject;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\ResultFactory;
use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
use Magento\Quote\Model\Quote\Address\RateResult\Method;
use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Psr\Log\LoggerInterface;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\HTTP\Client\CurlFactory;

/**
 * @category   uafrica
 * @package    uafrica_Customshipping
 * @author     info@bob.co.za
 * @website    https://www.bob.co.za
 */
class Customshipping extends AbstractCarrier implements CarrierInterface
{
    /**
     * Carrier's code
     *
     * @var string
     */
    protected $_code = 'uafrica';

    /**
     * Whether this carrier has fixed rates calculation
     *
     * @var bool
     */
    protected $_isFixed = false;

    /**
     * @var ResultFactory
     */
    protected $_rateResultFactory;

    /**
     * @var MethodFactory
     */
    protected $_rateMethodFactory;



    //TODO: REFACTOR THIS
    /**
     * @var \Magento\Framework\Controller\Result\JsonFactory
     */
    protected $jsonFactory;

    /**
     * @var \Magento\Framework\HTTP\Client\Curl
     */
    protected $curl;


    /**
     * @param \Magento\Framework\Controller\Result\JsonFactory $jsonFactory
     */

    /**
     * @param ScopeConfigInterface $scopeConfig
     * @param ErrorFactory $rateErrorFactory
     * @param LoggerInterface $logger
     * @param ResultFactory $rateResultFactory
     * @param MethodFactory $rateMethodFactory
     * @param array $data
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        ErrorFactory $rateErrorFactory,
        LoggerInterface $logger,
        ResultFactory $rateResultFactory,
        MethodFactory $rateMethodFactory,
        JsonFactory $jsonFactory,
        CurlFactory $curlFactory,
        array $data = []
    ) {
        $this->jsonFactory = $jsonFactory;
        $this->curl = $curlFactory->create();
        $this->_rateResultFactory = $rateResultFactory;
        $this->_rateMethodFactory = $rateMethodFactory;
        parent::__construct($scopeConfig, $rateErrorFactory, $logger, $data);
    }


    /**
     *  Allow Admin/User to track shipment from admin panel or frontend  order page i.e popup
     *  @return bool
     */
    public function isTrackingAvailable(): bool
    {
        return true;
    }

    /**
     * Get allowed shipping methods
     *
     *  @param string $type
     *  @param string $code
     *  @param array|false
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function getCode($type, string $code = '')
    {
        $codes = [
            'method' => [
                'uafrica_FIRST_INTERNATIONAL_PRIORITY' => __('uafrica First Priority'),
                'uafrica_1_DAY_FREIGHT' => __('1 Day Freight'),
                'uafrica_2_DAY_FREIGHT' => __('2 Day Freight'),
                'uafrica_2_DAY' => __('2 Day'),
                'uafrica_2_DAY_AM' => __('2 Day AM'),
                'uafrica_3_DAY_FREIGHT' => __('3 Day Freight'),
                'uafrica_EXPRESS_SAVER' => __('Express Saver'),
                'uafrica_GROUND' => __('Ground'),
                'FIRST_OVERNIGHT' => __('First Overnight'),
                'GROUND_HOME_DELIVERY' => __('Home Delivery'),
                'INTERNATIONAL_ECONOMY' => __('International Economy'),
                'INTERNATIONAL_ECONOMY_FREIGHT' => __('Intl Economy Freight'),
                'INTERNATIONAL_FIRST' => __('International First'),
                'INTERNATIONAL_GROUND' => __('International Ground'),
                'INTERNATIONAL_PRIORITY' => __('International Priority'),
                'INTERNATIONAL_PRIORITY_FREIGHT' => __('Intl Priority Freight'),
                'PRIORITY_OVERNIGHT' => __('Priority Overnight'),
                'SMART_POST' => __('Smart Post'),
                'STANDARD_OVERNIGHT' => __('Standard Overnight'),
                'uafrica_FREIGHT' => __('Freight'),
                'uafrica_NATIONAL_FREIGHT' => __('National Freight'),
            ],
            'dropoff' => [
                'REGULAR_PICKUP' => __('Regular Pickup'),
                'REQUEST_COURIER' => __('Request Courier'),
                'DROP_BOX' => __('Drop Box'),
                'BUSINESS_SERVICE_CENTER' => __('Business Service Center'),
                'STATION' => __('Station'),
            ],
            'packaging' => [
                'uafrica_ENVELOPE' => __('uafrica Envelope'),
                'uafrica_PAK' => __('uafrica Pak'),
                'uafrica_BOX' => __('uafrica Box'),
                'uafrica_TUBE' => __('uafrica Tube'),
                'uafrica_10KG_BOX' => __('uafrica 10kg Box'),
                'uafrica_25KG_BOX' => __('uafrica 25kg Box'),
                'YOUR_PACKAGING' => __('Your Packaging'),
            ],
            'containers_filter' => [
                [
                    'containers' => ['uafrica_ENVELOPE', 'uafrica_PAK'],
                    'filters' => [
                        'within_us' => [
                            'method' => [
                                'uafrica_EXPRESS_SAVER',
                                'uafrica_2_DAY',
                                'uafrica_2_DAY_AM',
                                'STANDARD_OVERNIGHT',
                                'PRIORITY_OVERNIGHT',
                                'FIRST_OVERNIGHT',
                            ],
                        ],
                        'from_us' => [
                            'method' => ['INTERNATIONAL_FIRST', 'INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'],
                        ],
                    ],
                ],
                [
                    'containers' => ['uafrica_BOX', 'uafrica_TUBE'],
                    'filters' => [
                        'within_us' => [
                            'method' => [
                                'uafrica_2_DAY',
                                'uafrica_2_DAY_AM',
                                'STANDARD_OVERNIGHT',
                                'PRIORITY_OVERNIGHT',
                                'FIRST_OVERNIGHT',
                                'uafrica_FREIGHT',
                                'uafrica_1_DAY_FREIGHT',
                                'uafrica_2_DAY_FREIGHT',
                                'uafrica_3_DAY_FREIGHT',
                                'uafrica_NATIONAL_FREIGHT',
                            ],
                        ],
                        'from_us' => [
                            'method' => ['INTERNATIONAL_FIRST', 'INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'],
                        ],
                    ],
                ],
                [
                    'containers' => ['uafrica_10KG_BOX', 'uafrica_25KG_BOX'],
                    'filters' => [
                        'within_us' => [],
                        'from_us' => ['method' => ['INTERNATIONAL_PRIORITY']],
                    ],
                ],
                [
                    'containers' => ['YOUR_PACKAGING'],
                    'filters' => [
                        'within_us' => [
                            'method' => [
                                'uafrica_GROUND',
                                'GROUND_HOME_DELIVERY',
                                'SMART_POST',
                                'uafrica_EXPRESS_SAVER',
                                'uafrica_2_DAY',
                                'uafrica_2_DAY_AM',
                                'STANDARD_OVERNIGHT',
                                'PRIORITY_OVERNIGHT',
                                'FIRST_OVERNIGHT',
                                'uafrica_FREIGHT',
                                'uafrica_1_DAY_FREIGHT',
                                'uafrica_2_DAY_FREIGHT',
                                'uafrica_3_DAY_FREIGHT',
                                'uafrica_NATIONAL_FREIGHT',
                            ],
                        ],
                        'from_us' => [
                            'method' => [
                                'INTERNATIONAL_FIRST',
                                'INTERNATIONAL_ECONOMY',
                                'INTERNATIONAL_PRIORITY',
                                'INTERNATIONAL_GROUND',
                                'uafrica_FREIGHT',
                                'uafrica_1_DAY_FREIGHT',
                                'uafrica_2_DAY_FREIGHT',
                                'uafrica_3_DAY_FREIGHT',
                                'uafrica_NATIONAL_FREIGHT',
                                'INTERNATIONAL_ECONOMY_FREIGHT',
                                'INTERNATIONAL_PRIORITY_FREIGHT',
                            ],
                        ],
                    ],
                ],
            ],
            'delivery_confirmation_types' => [
                'NO_SIGNATURE_REQUIRED' => __('Not Required'),
                'ADULT' => __('Adult'),
                'DIRECT' => __('Direct'),
                'INDIRECT' => __('Indirect'),
            ],
            'unit_of_measure' => [
                'LB' => __('Pounds'),
                'KG' => __('Kilograms'),
            ],
        ];

        if (!isset($codes[$type])) {
            return false;
        } elseif ('' === $code) {
            return $codes[$type];
        }

        if (!isset($codes[$type][$code])) {
            return false;
        } else {
            return $codes[$type][$code];
        }

    }

    /**
     * Whether this carrier has shipping labels
     */
    public function isShippingLabelsAvailable(): bool
    {
        return true;
    }

    /**
     * @param string $tracking
     * @return DataObject
     */
    public function getTrackingInfo($tracking): DataObject
    {
        //Not Used Yet On This Phase of Development
        //  $result = $this->_trackFactory->create();
        $result = new DataObject();
        //Insert tracking code dynamically here
        $result->setUrl('https://api.dev.ship.uafrica.com/tracking?channel=localhost&tracking_reference='.$tracking);
        $result->setTracking($tracking);

        $result->setCarrierTitle($this->getConfigData('title'));

        //Perform curl request to get tracking info from uAfrica API
        //Inject tracking code into the url dynamically
        $this->curl->get('https://api.dev.ship.uafrica.com/tracking?channel=localhost&tracking_reference='.$tracking);

        $response = $this->curl->getBody();

        $response = json_decode($response, true);

        $result->addData((array)$response);
        /**1. Image to be dynamic in the next phase
         * 2. Tracking status to be dynamic in the next phase
         * 3. This method feels hacky, not sure if I will need to refactor, but it works for now,
         * I am open for suggestions.
         */
        echo "<pre>";
                print_r("
        <img src='https://ik.imagekit.io/z1viz85yxs/dev-v3/provider-logos/devpanda_logo.png' alt='Dev Panda' width='100' height='100'>

                <table '>
                <tr>
                <th>Order Number</th>
                <th>Order Date</th>
                <th>Order Status</th>
                </tr>
                <tr>
                <td>".$response[0]['order_number']."</td>
                <td>".$response[0]['shipment_time_created']."</td>
                <td>".$response[0]['status_friendly']."</td>
                </tr>
                </table>

                <h4>Tracking</h4>
                <table>
                <tr>
                <th>Tracking Number</th>
                <th>Tracking Status</th>
                <th>Tracking Date</th>
                </tr>
                <tr>
                <td>".$response[0]['shipment_tracking_reference']."</td>
                <td>".$response[0]['status_friendly']."</td>
                <td>".$response[0]['last_checkpoint_time']."</td>
                </tr>
                </table>

        ");

      print_r(" <h4>Checkpoints</h4>
        <table>
            <tr>
                <th>Status</th>
                <th>Status Friendly</th>
                <th>Country</th>
                <th>Zone</th>
                <th>City</th>
                <th>Zip</th>
                <th>Location</th>
                <th>Message</th>
                <th>Time</th>
            </tr>"
      );
        foreach ($response[0]['checkpoints'] as $checkpoint) {
            print_r("<tr>
                <td>" . $checkpoint['status'] . "</td>
                <td>" . $checkpoint['status_friendly'] . "</td>
                <td>" . $checkpoint['country'] . "</td>
                <td>" . $checkpoint['zone'] . "</td>
                <td>" . $checkpoint['city'] . "</td>
                <td>" . $checkpoint['zip'] . "</td>
                <td>" . $checkpoint['location'] . "</td>
                <td>" . $checkpoint['message'] . "</td>
                <td>" . $checkpoint['time'] . "</td>
            </tr>
            ");

        }
       print_r("</table>");

        echo "</pre>";

        return $result;
    }

    /**
     * @return string
     */
    private function getApiUrl(): string
    {
        //return $this->getConfigData('api_url');
       // return 'https://api.dev.ship.uafrica.com';

        //Used for testing purposes only on localhost, since there is not endpoint to get magento rates to work with
        //Basically, I am using the structure of the response from the uAfrica API to test the functionality of the module
        return 'https://8390956f-c00b-497d-8742-87b1d6305bd2.mock.pstmn.io/putrates';
    }

    /**
     * Make request to uAfrica API to get shipping rates
     *  @return array
     */
    private function getRates($payload): array
    {
        $this->curl->post($this->getApiUrl(), $payload);

        $response = $this->curl->getBody();

        $response = json_decode($response, true);

        return $response;
    }

    /**
     * Collect and get rates for storefront
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     * @param RateRequest $request
     * @return DataObject|bool|null
     * @api
     */
    public function collectRates(RateRequest $request)
    {
        //TODO: You need to work with this function in order to implement getting rates at checkout
        /**
         * Make sure that Shipping method is enabled
         */
        if (!$this->isActive()) {
            return false;
        }

        /** @var \Magento\Shipping\Model\Rate\Result $result */

        $result = $this->_rateResultFactory->create();

        //TODO: Get the rates from the API and append them to the result object
        //JSON data fed to post man mock server as a response to the request for rates
        //{
        //"rates": [
        //{
        //"id": "113810",
        //"description": "Standard Economy Shipping Rate",
        //"service_name": "Courier Door to Door Delivery - Economy",
        //"service_code": "113810_23",
        //"total_price": 7500,
        //"currency": "ZAR",
        //"min_delivery_date": "2022-12-29",
        //"max_delivery_date": "2023-01-03"
        //}
        //]
        //}
        //Mock URL FOR NOW, will be replaced with the actual API URL
        //Like; $this->getConfigData('api_url')
        //Fill in the payload with the data from the request


        //TODO: Get the rates from the API and append them to the result object
        //JSON data fed to post man mock server as a response to the request for rates
        //{
        //"rates": [
        //{
        //"id": "113810",
        //"description": "Standard Economy Shipping Rate",
        //"service_name": "Courier Door to Door Delivery - Economy",
        //"service_code": "113810_23",
        //"total_price": 7500,
        //"currency": "ZAR",
        //"min_delivery_date": "2022-12-29",
        //"max_delivery_date": "2023-01-03"
        //}
        //]
        //}
        //Mock URL FOR NOW, will be replaced with the actual API URL
        //Like; $this->getConfigData('api_url')
        //GET ALL DESTINATION DATA FROM THE REQUEST
        $destination = $request->getDestPostcode();
        $destCountry = $request->getDestCountryId();
        $destRegion = $request->getDestRegionCode();
        $destCity = $request->getDestCity();
        $destStreet = $request->getDestStreet();
        $destStreet1 = $destStreet;
        $destStreet2 = $destStreet;

        //Get all the origin data from the request
        $origin = $this->getConfigData('origin_postcode');
        $originCountry = $this->getConfigData('origin_country_id');
        $originRegion = $this->getConfigData('origin_region_id');
        $originCity = $this->getConfigData('origin_city');
        $originStreet = $this->getConfigData('origin_street');
        $originStreet1 = $originStreet;
        $originStreet2 = $originStreet;


        $items = $request->getAllItems();
        $itemsArray = [];
        foreach ($items as $item) {
            $itemsArray[] = [
                'name' => $item->getName(),
                'sku' => $item->getSku(),
                'quantity' => $item->getQty(),
                'price' => $item->getPrice(),
                'grams' => $item->getWeight() * 1000,
                'requires_shipping' => $item->getIsVirtual(),
                'taxable' => true,
                'fulfillment_service' => 'manual',
                'properties' => [],
                'vendor' => $item->getStoreId(),
                'product_id' => $item->getProductId(),
                'variant_id' => $item->getProduct()->getId()
            ];
        }
            $payload = [
                'rate' => [
                    //TODO: Get the data from the request object
                    'origin' => [
                        'country' => $originCountry,
                        'postal_code' => $origin,
                        'province' => $originRegion,
                        'city' => $originCity,
                        'name' => 'Gundo',
                        'address1' => $originStreet1,
                        'address2' => $originStreet2,
                        'address3' => '',
                        'phone' => '+27313039670',
                        'fax' => '',
                        'email' => '',
                        'address_type' => '',
                        'company_name' => 'Jam Clothing'
                    ],
                    //TODO: Get the destination from the request
                    'destination' => [
                        'country' => $destCountry,
                        'postal_code' => $destination,
                        'province' => $destRegion,
                        'city' => $destCity,
                        'name' => 'Brian Singh',
                        'address1' => $destStreet1,
                        'address2' => $destStreet2,
                        'address3' => '',
                        'phone' => '081 346 5923',
                        'fax' => '',
                        'email' => '',
                        'address_type' => '',
                        'company_name' => ''
                    ],
                    'items' => $itemsArray,
                    'currency' => 'ZAR',
                    'locale' => 'en-PT'
                ]
            ];

        $rates = $this->getRates($payload);

        $method = $this->_rateMethodFactory->create();

        foreach ($rates['rates'] as $code => $title) {
            $method->setCarrier('uafrica');
            $method->setCarrierTitle('uafrica');
            $method->setMethod($code);
            $method->setMethodTitle($title['service_name']);
            //Convert total price from cents to dollars
            $method->setPrice($title['total_price'] / 100);
            $method->setCost($title['total_price'] / 100);
            $result->append($method);
        }

        return $result;
    }

    /**
     *Get Allowed shipping methods (for this part make fake methods)
     * @return array
     *
     */
    public function getAllowedMethods(): array
    {
        $arr = [
            'method' => 'uafrica',

        ];
        //TODO: Get the allowed methods from the API and return them

        //Get shipping methods dynamically from the API
//        $arr = [];
//        $rates = $this->getRates();
//
//        foreach ($rates['rates'] as $code => $title) {
//            $arr[$code] = $title['service_name'];
//        }
        return $arr;
    }

}