<?php

namespace App\Classes\Modules\PackingLists\Processors;

use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Orders\Services\FetchesDataFromVTPortal;
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\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\Schedules\DataTransferObjects\ScheduleObject;
use App\Classes\Modules\Schedules\Services\CreatesSchedule;
use App\Classes\Modules\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
use App\Classes\Modules\Unity\Services\UpdatesContractObligation;
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\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;

class FetchContainersStatusUpdateFromVTPortalProcessor
{

    /** @var FetchesDataFromVTPortal */
    private $fetchesDataFRomVTPortal;

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

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

    /** @var UpdatesContractObligation */
    private $updatesContractObligations;

    /**
     * FetchContainersStatusUpdateFromVTPortalProcessor constructor.
     * @param FetchesDataFromVTPortal $fetchesDataFRomVTPortal
     * @param CreatesTransport $createsTransport
     * @param CreatesSchedule $createsSchedule
     * @param UpdatesContractObligation $updatesContractObligations
     */
    public function __construct(FetchesDataFromVTPortal $fetchesDataFRomVTPortal, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule, UpdatesContractObligation $updatesContractObligations)
    {
        $this->fetchesDataFRomVTPortal = $fetchesDataFRomVTPortal;
        $this->createsTransport = $createsTransport;
        $this->createsSchedule = $createsSchedule;
        $this->updatesContractObligations = $updatesContractObligations;
    }


    /**
     * @return array
     */
    public function execute(){

        try {
            $containers = Container::where('status', '=', ApprovalStatus::PENDING_VERIFICATION)->get();

            /** @var Container $container */
            foreach($containers as $container){
                try {
                    $filter = '["RefNo:=%js%\"'.$container->reference.'\"\u0000"]';

                    $containerDetailsRequest = $this->fetchesDataFRomVTPortal->clientRequest('http://portal.vtnation.com.my/Services/DataControllerService.asmx/GetPage', 'POST', json_decode('{"controller":"VCustomercontainer","view":"grid1","request":{"PageIndex":-1,"PageSize":10000,"SortExpression":"CreatedOn asc","Filter":'.$filter.'}}'), '');

                    $containerDetails = $this->fetchesDataFRomVTPortal->getResponseBody($containerDetailsRequest);

                    $containerDetails = $containerDetails->Rows[0];

                    if(!$eta = $containerDetails[3]){
                        continue;
                    }

                    $eta = Carbon::parse($eta);

                    $etd = Carbon::parse($eta)->subDays(5);

                    $delayDate = $containerDetails[6];

                    $containerStatus = $containerDetails[9];

                    $unstuffingDate = $containerDetails[7];

                    $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));
                    }

                    if($delayDate){

                        $delayDate = Carbon::parse($delayDate);
                        $transport = $container->transports()->first();

                        if(!$transport->schedules()->where('eta', '=', $delayDate)->first()) {
                            $etd = $transport->schedules()->where('status', '=', ApprovalStatus::APPROVED)->first()->etd;
                            $transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);
                            $this->createsSchedule->execute($transport, new ScheduleObject($etd, $delayDate, ApprovalStatus::APPROVED));
                        }

                    }

                    if($containerStatus === 'Unstuffing'){
                        $container->update(['status' => ApprovalStatus::COMPLETED]);
                        $container->transports()->first()->update(['drop_date' => Carbon::parse($unstuffingDate)->subDay(), 'status' => ApprovalStatus::COMPLETED]);

                        /** @var PackingList $packingList */
                        foreach($container->packingLists as $packingList){

                            if($packingList->status === ApprovalStatus::PENDING_VERIFICATION){
                                $packingList->status = ApprovalStatus::APPROVED;
                                $packingList->save();
                            }

                            $signature = $packingList->owner->orderRoles()->where('role_id', '=', OrderRoleTypes::SUPERVISOR)->first()->appointee->entity_sigiture;
                            foreach($packingList->steps()->where('reference', '!=', 'DELIVERY')->get() as $step){
                                $this->updatesContractObligations->execute($signature, $step->obligation_hash_id);
                                $step->update(['status' => ApprovalStatus::COMPLETED]);
                            }
                        }
                    }

                } catch (GuzzleException $exception) {
                    continue;
                }

            }
        } catch (\Exception $exception) {
            Log::error($exception);
        }

        return [];

    }


}
