<?php

namespace App\ShippingMethods;

use App\Interfaces\ShippingMethodInterface;
use App\Models\Setting;
use App\Services\General\CurlService;
use Carbon\Carbon;
use Illuminate\Support\Str;

class UpsShippingMethod implements ShippingMethodInterface
{
    protected array $params = [];
    private string $url;
    //private bool $isLive;
    private string $clientId;
    private string $clientSecret;
    private string $shipperNumber;
    private mixed $accessToken;
    private string $version = "v1";

    public function __construct()
    {
        //$this->isLive = config('services.shipping.ups.is_live');
        $this->url = config('services.shipping.ups.url');
        $this->clientId = config('services.shipping.ups.client_id');
        $this->clientSecret = config('services.shipping.ups.client_secret');
        $this->shipperNumber = config('services.shipping.ups.shipper_number');
        $this->createToken();
    }

    /**
     * @return void
     */
    private function createToken(): void
    {
        $settings = settings(['ups_access_token', 'ups_expiry_date']);
        $ups_access_token = $settings['ups_access_token'] ?? null;
        $ups_expiry_date  = $settings['ups_expiry_date'] ?? null;
        $this->accessToken = $ups_access_token;
        if (Carbon::now()->gte($ups_expiry_date) || !$ups_expiry_date) {
            $this->refreshToken();
        }
    }

    /**
     * @return array
     */
    private function refreshToken(): array
    {
        $success = true;
        $data = null;
        $curlService = new CurlService(false);
        $headers = [
            'Content-Type: application/x-www-form-urlencoded', // Http::asForm() // http_build_query([])
            'Authorization: Basic ' . base64_encode("$this->clientId:$this->clientSecret"),
        ];
        $requestData = ['grant_type' => 'client_credentials'];
        $responseResult = [];
        try {
            $responseResult = $curlService->post($this->url . 'security/v1/oauth/token', http_build_query($requestData), $headers);
            $message = $responseResult['errors'] ?: ($responseResult['response']['response']['errors'][0]['message'] ?? null);
        } catch (\Exception $e) {
            $success = false;
            $message = $e->getMessage();
        }
        //dd($responseResult, $success, $message);
        $statusCode = $responseResult['status_code'] ?? 0;
        if ($statusCode == 200) {
            $response = $data = $responseResult['response'] ?? [];
            $issued_at = $response['issued_at'];
            $access_token = $response['access_token'];
            $expires_in = $response['expires_in']; //4 hours
            Setting::where('key', 'ups_expiry_date')->update(['value' => Carbon::createFromTimestamp($issued_at / 1000)->addSeconds($expires_in)]);
            Setting::where('key', 'ups_access_token')->update(['value' => $access_token]);
            $this->accessToken = $access_token;
        } else {
            $success = false;
        }
        return [
            'success' => $success,
            'message' => $message,
            'data' => $data,
        ];
    }

    public function processShipping(array $params = [])
    {
        $success = true;
        $this->params = $params;
        $order = $params['order'] ?? null;
        $curlService = new CurlService();
        $headers = [
            'transId: ',
            'transactionSrc: testing',
            'Content-Type: application/json',
            "Authorization: Bearer $this->accessToken",
        ];
        $requestData = $this->prepareCreateShipmentData();
        $responseResult = [];
        try {
            $responseResult = $curlService->post($this->url . "api/shipments/$this->version/ship", json_encode($requestData), $headers);
            $message = $responseResult['errors'] ?: ($responseResult['response']['response']['errors'][0]['message'] ?? null);
        } catch (\Exception $e) {
            $success = false;
            $message = $e->getMessage();
        }
        //dd($requestData, $responseResult, $success, $message);
        $statusCode = $responseResult['status_code'] ?? 0;
        $response = $data = $responseResult['response'] ?? [];
        $responseStatusCode = $response['ShipmentResponse']['Response']['ResponseStatus']['Code'] ?? 0;
        if ($statusCode == 200 && $responseStatusCode == 1) {
            $shipmentResults = $response['ShipmentResponse']['ShipmentResults'] ?? [];
            $shipmentIdentificationNumber = $shipmentResults['ShipmentIdentificationNumber'] ?? null;
            $totalCharges = $shipmentResults['ShipmentCharges']['TotalCharges']['MonetaryValue'] ?? null;
            $trackingNumber = $shipmentResults['PackageResults']['TrackingNumber'] ?? null;
            $shippingLabel = $shipmentResults['PackageResults']['ShippingLabel'];
            $imageFormat = $shippingLabel['ImageFormat']['Code'];
            $graphicImage = $shippingLabel['GraphicImage'];

            //start update order
            $order->update([
                'ups_shipment_identification_number' => $shipmentIdentificationNumber,
                'ups_tracking_number' => $trackingNumber,
                'ups_total_charges' => $totalCharges,
                'ups_label_file' => convertBase64StringToFile($graphicImage ?? null, 'images/orders/', $imageFormat ?? null),
                'ups_response' => $response,
            ]);
            //end update order
        } else {
            $success = false;
        }
        return [
            'success' => $success,
            'message' => $message,
            'data' => $data,
        ];
    } //end of method

    /**
     * @return array
     */
    private function prepareCreateShipmentData(): array
    {
        $requestData = $this->params['request_data'] ?? null;
        $session = $this->params['session'] ?? null;
        $order = $this->params['order'] ?? null;
        $orderPayment = $this->params['order_payment'] ?? null;

        //$siteAddressLine = 'جدة-حى البساتين-شارع الامير سلطان'; //35 char only
        //$siteAddressLine = 'Jeddah - Al-Basateen District - Prince Sultan Street'; //35 char only
        $siteAddressLine = Str::limit('Basateen District Prince Sultan St.', 35, '');
        $sitePhone = '966555377367';
        $siteCity = 'JEDDAH';
        $sitePostalCode = '23717';
        $siteCountryCode = 'SA';
        $shipperName = 'City Bike Company for Motorcycle'; //35 char only
        $addressDetails = Str::limit($order->address->address->address ?? "Saudi Arabia - Jeddah", 35, '');
        //$countryName = Str::limit($order->address->address->country->currentDescription->name ?? "Saudi Arabia", 30, '');
        $cityName = Str::limit($order->address->address->city->currentDescription->name ?? "Jeddah", 30, '');
        $countryCode = $order->address->address->country->iso ?? "SA";
        $userName = $order->user->name  ?? "test";
        //$userEmail = $order->user->email ?? "test@yahoo.com";
        $userPhone = $order->user->phone ?? "96655555555";

        return [
            'ShipmentRequest' => [
                'Request' => [
                    'SubVersion' => '1801',
                    'RequestOption' => 'nonvalidate',
                    'TransactionReference' => [
                        'CustomerContext' => ''
                    ]
                ],
                'Shipment' => [
                    'Description' => 'Motorcycle accessories and helmets',
                    'Shipper' => [
                        'Name' => $shipperName,
                        'AttentionName' => $shipperName,
                        'TaxIdentificationNumber' => '123456',
                        'Phone' => [
                            'Number' => $sitePhone,
                            'Extension' => ' ',
                        ],
                        'ShipperNumber' => $this->shipperNumber,
                        'FaxNumber' => '8002222222',
                        'Address' => [
                            'AddressLine' => $siteAddressLine,
                            'City' => $siteCity,
                            'StateProvinceCode' => 'MD',
                            'PostalCode' => $sitePostalCode,
                            'CountryCode' => $siteCountryCode,
                        ]
                    ],
                    'ShipTo' => [
                        'Name' => $userName,
                        'AttentionName' => $userName,
                        'Phone' => [
                            'Number' => $userPhone,
                        ],
                        'Address' => [
                            'AddressLine' => $addressDetails,
                            'City' => $cityName,
                            'StateProvinceCode' => 'MD',
                            'PostalCode' => '21030',
                            'CountryCode' => $countryCode,
                        ],
                        'Residential' => ' '
                    ],
                    'ShipFrom' => [
                        'Name' => $shipperName,
                        'AttentionName' => $shipperName,
                        'Phone' => [
                            'Number' => $sitePhone,
                        ],
                        'FaxNumber' => '1234567890',
                        'Address' => [
                            'AddressLine' => $siteAddressLine,
                            'City' => $siteCity,
                            'StateProvinceCode' => 'GA',
                            'PostalCode' => $sitePostalCode,
                            'CountryCode' => $siteCountryCode,
                        ],
                    ],
                    'PaymentInformation' => [
                        'ShipmentCharge' => [
                            'Type' => '01',
                            'BillShipper' => [
                                'AccountNumber' => $this->shipperNumber,
                            ],
                        ]
                    ],
                    'Service' => [
                        'Code' => '65',
                        'Description' => 'UPS Worldwide Saver',
                    ],
                    'Package' => [
                        'Description' => " ",
                        'Packaging' => [
                            'Code' => '02',
                            'Description' => 'Nails',
                        ],
                        'Dimensions' => [
                            'UnitOfMeasurement' => [
                                'Code' => 'CM',
                                'Description' => 'Centimeter'
                            ],
                            'Length' => '25',
                            'Width' => '25',
                            'Height' => '50',
                        ],
                        'PackageWeight' => [
                            'UnitOfMeasurement' => [
                                'Code' => 'KGS',
                                'Description' => 'Kilograms'
                            ],
                            'Weight' => '1'
                        ],
                    ],
                    //'Locale' => '', // en_GB (default)
                ],
                'LabelSpecification' => [
                    'LabelImageFormat' => [
                        'Code' => 'GIF',
                        'Description' => 'GIF'
                    ],
                    'HTTPUserAgent' => 'Mozilla/4.5',
                    //'CharacterSet' => '', // eng (default)
                ],
            ]
        ];
    } //end of method

} //end of class
