<?php
/**
 * Created by PhpStorm.
 * User: cbarranco
 * Date: 3/28/2017
 * Time: 12:09 PM
 */

namespace Hilco\Shipments;


use Carbon\Carbon;
use Hilco\Models\Carrier;
use Hilco\Models\CustomerShippingAddress;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use RocketShipIt\Rate as RocketShipItRate;
use RocketShipIt\TimeInTransit;

class ShipmentManager
{
    protected $carriers;

    public function __construct() {
        $this->carriers = new Collection;
    }

    public function getWebCartRates(CustomerShippingAddress $customerShippingAddress) {
        $cartComposer = App::make('cartSingleton');
        $cartStatus = $cartComposer->getCartStatus();
        $activeWebSilo = b2b()->activeWebSilo;
        $rateType = \Illuminate\Support\Arr::get($activeWebSilo, 'shipment_rate_type', 'api');
        $rates = new Collection;

        if ($rateType == 'api'){
            $rates = $this->getWebCartApiRates($cartStatus, $customerShippingAddress);
        } else {
            $siloRates = \Illuminate\Support\Arr::get($this->activeWebSilo, 'shipmentFlatRates', false);
            krsort($siloRates);
            $cartValue = 0;
            if ($rateType == 'flatByWeight') $cartValue = \Illuminate\Support\Arr::get($cartStatus, 'totalWeight', 0);
            if ($rateType == 'flatByPrice') $cartValue = \Illuminate\Support\Arr::get($cartStatus, 'discountedTotal', 0);
            foreach ($siloRates as $threshold => $siloRate) {
                if ($cartValue >= $threshold) {
                    $rates->push(new Rate(null, null, $siloRate, $siloRate));
                    break;
                }
            }
        }

        return $rates;
    }

    protected function getWebCartApiRates($cartStatus, CustomerShippingAddress $customerShippingAddress) {
        $defaultPlant = $customerShippingAddress->plant;
        $fromZipCode = \Illuminate\Support\Arr::get($defaultPlant, 'plantAddress.zip');
        $packages = [];

        foreach (\Illuminate\Support\Arr::get($cartStatus, 'items', []) as $cartItem) {
            $part = \Illuminate\Support\Arr::get($cartItem, 'part');
            if ($part->inStockForPlant($defaultPlant)) {
                \Illuminate\Support\Arr::set($packages, 'inStock.weight', $part->weight_lbs * \Illuminate\Support\Arr::get($cartItem, 'quantity', 0));
                \Illuminate\Support\Arr::set($packages, 'inStock.volume', $part->vol_ci * \Illuminate\Support\Arr::get($cartItem, 'quantity', 0));
            } else {
                \Illuminate\Support\Arr::set($packages, 'backordered.weight', $part->weight_lbs * \Illuminate\Support\Arr::get($cartItem, 'quantity', 0));
                \Illuminate\Support\Arr::set($packages, 'backordered.volume', $part->vol_ci * \Illuminate\Support\Arr::get($cartItem, 'quantity', 0));
            }
        }

        foreach ($packages as $package) {

        }
    }

    public function getApiRates(Collection $carriers, $package) {
        $this->carriers = $carriers;
        $rates = new Collection;
        $apiCarriers = $carriers->keyBy('api_carrier');
        $apiRates = [];
        foreach ($apiCarriers as $carrier) {
            $apiCarrier = $carrier->api_carrier;
            switch ($apiCarrier) {
                case 'UPS':
                    $apiRates[$apiCarrier] = $this->getRateForUpsCarrier($package, $carrier->residential);
                    break;
                case 'USPS':
                    $apiRates[$apiCarrier] = $this->getRateForUspsCarrier($package, $carrier->residential);
                    break;
            }
        }

        foreach ($apiRates as $apiCarrier => $apiCarrierRates) {
            foreach ($apiCarrierRates as $carrierCode => $apiRate) {
                $rate = new Rate();
                $rate->package = $package;
                $rate->carrier = $this->carriers->keyBy('carrier_code')->get($carrierCode);
                $rate->base_rate = (float)\Illuminate\Support\Arr::get($apiRate, 'rate', 0);
                $rate->discounted_rate = (float)$rate->base_rate * (1 - ($rate->carrier->discount/100));
                $rate->delivery_datetime = Carbon::parse(\Illuminate\Support\Arr::get($apiRate, 'delivery_date') . ' ' . \Illuminate\Support\Arr::get($apiRate, 'delivery_time'));
                $rate->guaranteed = \Illuminate\Support\Arr::get($apiRate, 'guaranteed', false);
                $rates->put($carrierCode, $rate);
            }
        }

        return $rates;
    }

    protected function callRocketShipIt($apiCarrier, $toCountry, $weight, $volume, $fromZipCode, $toZipCode, $isResidential) {
        $rate = new RocketShipItRate($apiCarrier);
        $rate->setParameter('shipCountry', 'US');
        $rate->setParameter('toCountry', $toCountry);

        $rate->setParameter('weightUnit', 'LBS');
        $rate->setParameter('weight', max(1, $weight));

        $rate->setParameter('lengthUnit', 'IN');
        $rate->setParameter('volume', $volume);

        $rate->setParameter('currency', 'USD');
        $rate->setParameter('shipCode', $fromZipCode);
        $rate->setParameter('toCode', $toZipCode);

        $rate->setParameter('residentialAddressIndicator', $isResidential);

        $rateResponse = $rate->getAllRates();

        $transit = new TimeInTransit($apiCarrier);

        $transit->setParameter('shipCountry', 'US');
        $transit->setParameter('shipCode', $fromZipCode);

        $transit->setParameter('toCountry', $toCountry);
        $transit->setParameter('toCode', $toZipCode);

        $transit->setParameter('weightUnit', 'LBS');
        $transit->setParameter('weight', $weight);
        $transit->setParameter('saturdayDelivery', 'YES');

        $transit->setParameter('lengthUnit', 'IN');
        $transit->setParameter('volume', $volume);

        $transit->setParameter('pickupDate', date('Y-m-d'));

        $transitResponse = $transit->getTimeInTransit();
        return [
            'rates' => $rateResponse,
            'transit' => $transitResponse,
        ];
    }

    protected function getRateForUpsCarrier(Package $package, $isResidential) {
        $apiInfo = $this->callRocketShipIt('UPS', $package->country, $package->weight, $package->volume, $package->fromZipCode, $package->zipCode, $isResidential);

        $rateInfo = [];
        foreach (\Illuminate\Support\Arr::get($apiInfo, 'rates.RatingServiceSelectionResponse.RatedShipment', []) as $ratedShipment) {
            $apiCode = \Illuminate\Support\Arr::get($ratedShipment, 'Service.Code');
            $carriers = $this->carriers->where('api_code', $apiCode);
            foreach ($carriers as $carrier) {
                $carrierCode = $carrier->carrier_code;
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.rate", \Illuminate\Support\Arr::get($ratedShipment, 'TotalCharges.MonetaryValue'));
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.api_code", $apiCode);
            }
        }

        foreach (\Illuminate\Support\Arr::get($apiInfo, 'transit.TimeInTransitResponse.TransitResponse.ServiceSummary', []) as $transitService) {
            $transitCode = \Illuminate\Support\Arr::get($transitService, 'Service.Code');
            $carriers = $this->carriers->where('transit_code', $transitCode);
            foreach ($carriers as $carrier) {
                $carrierCode = $carrier->carrier_code;
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.transit_code", $transitCode);
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.delivery_date", date('Y-m-d', strtotime(\Illuminate\Support\Arr::get($transitService, 'EstimatedArrival.Date'))));
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.delivery_time", date('H:i', strtotime(\Illuminate\Support\Arr::get($transitService, 'EstimatedArrival.Time'))));
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.guaranteed", (\Illuminate\Support\Arr::get($transitService, 'Guaranteed.Code', 'N') == 'Y'));
            }
        }

        return $rateInfo;
    }

    protected function getRateForUspsCarrier(Package $package, $isResidential) {
        $apiInfo = $this->callRocketShipIt('USPS', 'US', $package->weight, $package->volume, $package->fromZipCode, $package->zipCode, $isResidential);

        $rateInfo = [];
        foreach (\Illuminate\Support\Arr::get($apiInfo, 'rates.RateV4Response.Package.Postage', []) as $ratedShipment) {
            $apiCode = \Illuminate\Support\Arr::get($ratedShipment, 'CLASSID');
            $carriers = $this->carriers->where('api_code', $apiCode);
            foreach ($carriers as $carrier) {
                $carrierCode = $carrier->carrier_code;
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.rate", \Illuminate\Support\Arr::get($ratedShipment, 'Rate'));
                \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.api_code", $apiCode);
            }
        }

        foreach (\Illuminate\Support\Arr::get($apiInfo, 'transit.ExpressMailCommitmentResponse', []) as $transitCode => $transitService) {
            $carriers = $this->carriers->where('transit_code', $transitCode);
            foreach ($carriers as $carrier) {
                $carrierCode = $carrier->carrier_code;
                if ($transitCode == 'ExpressMailCommitmentResponse') {
                    $commitment = \Illuminate\Support\Arr::get($transitService, 'Commitment.0', \Illuminate\Support\Arr::get($transitService, 'Commitment', []));
                    \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.delivery_date", date('Y-m-d', strtotime("+ " . str_replace("-", " ", \Illuminate\Support\Arr::get($commitment, 'CommitmentName')))));
                    \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.delivery_time", date('H:i', strtotime(\Illuminate\Support\Arr::get($commitment, 'CommitmentTime'))));
                    \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.guaranteed", true);
                } else {
                    \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.delivery_date", date('H:i', strtotime("+ " . \Illuminate\Support\Arr::get($transitService, 'Days') . ' weekdays')));
                    \Illuminate\Support\Arr::set($rateInfo, "$carrierCode.guaranteed", false);
                }
            }
        }

        return $rateInfo;
    }
}