<?php

namespace App\Classes\Modules\PackingLists\Processors;

use App\Classes\Exceptions\AccessForbiddenException;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\RequestValidationException;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Orders\Services\FetchesDataFromYDPortal;

use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\PackingLists\DataTransferObjects\ContainerObject;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackageObject;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject;
use App\Classes\Modules\PackingLists\Services\Containers\FetchesContainer;
use App\Classes\Modules\PackingLists\Services\FetchesPackingList;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Steps\DataTransferObjects\StepsObject;
use App\Classes\Modules\Steps\Services\CreatesStep;
use App\Classes\Modules\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
use App\Classes\Modules\Unity\Processors\ActivateContractProcessor;
use App\Classes\Modules\Unity\Processors\AssignContractEntityProcessor;
use App\Classes\Modules\Unity\Processors\CreateContractEntityProcessor;
use App\Classes\Modules\Unity\Services\CreatesContract;
use App\Classes\Modules\Unity\Services\UpdatesContractObligation;
use App\Classes\Modules\PerfexCRM\Processors\PackingListToPerfexCRMProcessor;
use App\Classes\Notifications\ShipmentDepartureEmail;
use App\Classes\Notifications\ShipmentRescheduleEmail;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\ContainerTypes;
use App\Classes\ValueObjects\Constants\OrderRoleTypes;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransportType;
use App\Classes\ValueObjects\Constants\WarehouseReferences;
use App\Classes\ValueObjects\Constants\PerfexCRMTasksYDStages;
use App\Models\Container;
use App\Models\Order;
use App\Models\PackingList;
use App\Models\Transport;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class FetchContainersFromYdPortalProcessor
{
    /** @var FetchesDataFromYDPortal */
    private $fetchesDataFRomYDPortal;

    /** @var CreatesTransport */
    private $createsTransport;

    /** @var CreatesSchedule */
    private $createsSchedule;

    /** @var FetchesContainer */
    private $fetchesContainer;

    /** @var CreateContainerProcessor */
    private $createContainerProcessor;

    /** @var PackingListToPerfexCRMProcessor */
    private $packingListToPerfexCRMProcessor;

    /**
     * @param FetchesDataFromYDPortal $fetchesDataFRomYDPortal
     * @param CreatesTransport $createsTransport
     * @param CreatesSchedule $createsSchedule
     * @param FetchesContainer $fetchesContainer
     * @param CreateContainerProcessor $createContainerProcessor
     * @param PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor
     */
    public function __construct(FetchesDataFromYDPortal $fetchesDataFRomYDPortal, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, FetchesContainer $fetchesContainer, CreateContainerProcessor $createContainerProcessor, PackingListToPerfexCRMProcessor $packingListToPerfexCRMProcessor)
    {
        $this->fetchesDataFRomYDPortal = $fetchesDataFRomYDPortal;
        $this->createsTransport = $createsTransport;
        $this->createsSchedule = $createsSchedule;
        $this->fetchesContainer = $fetchesContainer;
        $this->createContainerProcessor = $createContainerProcessor;
        $this->packingListToPerfexCRMProcessor = $packingListToPerfexCRMProcessor;
    }


    /**
     * @return void
     * @throws MalformedRequestException
     * @throws AccessForbiddenException
     * @throws RequestValidationException
     */
    public function execute()
    {
        $maxFetchTime = Carbon::now()->subMonths(4);
        $packingLists = PackingList::where('type', PackingListType::SHIPPING_PACKING_LIST)->whereDate('created_at', '>=', $maxFetchTime)->doesntHave('containers')->get();

        foreach ($packingLists as $packingList) {
            $time_start = microtime(true);

            $containerReference = null;
            $loadingDate = null;
            $etd = null;
            $eta = null;

            $trackingRequest = $this->fetchesDataFRomYDPortal->clientRequest('http://www.yd-wl.com/api/ApiTracking.ashx', 'GET', [
                'trakingno' => $packingList->reference
            ]);

            $rows = $this->fetchesDataFRomYDPortal->getResponseBody($trackingRequest);

            if(!$rows->data){
                continue;
            }

            foreach (array_reverse($rows->data) as $trackingRow) {
                if (strpos($trackingRow->tracking, '货物装柜完成。') !== false) {
                    $tracking = explode(':', $trackingRow->tracking);
                    $containerReference = explode('预计到港时间', $tracking[1])[0];
                    $loadingDate = Carbon::parse($trackingRow->trackingtime);
                    $etd = Carbon::parse($tracking[2])->subDays(5);
                     $eta = Carbon::parse($tracking[2]);
                }
            }

            if($containerReference) {
                try {
                    $container = $this->fetchesContainer->execute(['reference' => $containerReference]);
                    $container->packingLists()->detach($packingList);
                    $container->packingLists()->attach($packingList);
                } catch (ResourceNotFoundException $exception){

                    if(!($packingList->owner instanceof Order)) continue;

                    $originWarehouse = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_WAREHOUSE)->first()->appointee;


                    $containerObject = new ContainerObject($containerReference, '', '', ContainerTypes::FORTY_FEET_DRY_CONTAINER, $loadingDate, ApprovalStatus::PENDING_VERIFICATION);

                    /** @var Container $container */
                    $container = $this->createContainerProcessor->execute($containerObject, $originWarehouse);

                    $container->packingLists()->detach($packingList);
                    $container->packingLists()->attach($packingList);

                    if(config('perfexcrm.is_enabled') == 'true'){
                        $this->packingListToPerfexCRMProcessor->execute($packingList, PerfexCRMTasksYDStages::LOAD_CONTAINER);
                    }

                    $transport = $container->transports()->first();

                    if(!$transport){
                        $transportObject = new TransportObject(TransportType::SEA, null, null,  $etd, null, ApprovalStatus::APPROVED);
                        /** @var Transport $transport */
                        $transport = $this->createsTransport->execute($transportObject, $container);
                        $this->createsSchedule->execute($transport, new ScheduleObject($etd, $eta, ApprovalStatus::APPROVED));
                    }
                }
            }

            $time_end = microtime(true);

            $execution_time = ($time_end - $time_start)/60;

            echo 'successful => <b>Total Execution Time:</b> '.$execution_time.' Mins<br>';
        }

    }
}

