<?php

namespace App\Classes\Modules\PackingLists\Processors;

use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\Addresses\Processors\CreateAddressFromOldAddressProcessor;
use App\Classes\Modules\Addresses\Services\CleansOldAddress;
use App\Classes\Modules\Companies\Services\FetchesCompanyModule;
use App\Classes\Modules\Orders\Processors\CreateOrderProcessor;
use App\Classes\Modules\Orders\Services\FetchesDataFromVTPortal;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\PackingLists\ControllersLogic\Packages\CreatePackageLogic;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackageObject;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject;
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\Transports\DataTransferObjects\TransportObject;
use App\Classes\Modules\Transports\Services\CreatesTransport;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
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\Address;
use App\Models\CompanyModule;
use App\Models\OldOrders;
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 FetchWarehouseReceiveListFromVTPortalProcessor
{


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

    /** @var CleansOldAddress */
    private $cleansOldAddress;

    /** @var CreateAddressFromOldAddressProcessor */
    private $createAddressFromOldAddressProcessor;

    /** @var FetchesCompanyModule */
    private $fetchesCompanyModule;

    /** @var FetchesOrder */
    private $fetchesOrder;

    /** @var CreateOrderProcessor */
    private $createOrderProcessor;

    /** @var FetchesPackingList */
    private $fetchesPackingList;

    /** @var CreatePackingListProcessor */
    private $createPackingListProcessor;

    /** @var CreatePackageLogic */
    private $createPackage;

    /** @var CreatePackageProcessor */
    private $createPackageProcessor;

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

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

    /**
     * FetchWarehouseReceiveListFromVTPortalProcessor constructor.
     * @param FetchesDataFromVTPortal $fetchesDataFRomVTPortal
     * @param CleansOldAddress $cleansOldAddress
     * @param CreateAddressFromOldAddressProcessor $createAddressFromOldAddressProcessor
     * @param FetchesCompanyModule $fetchesCompanyModule
     * @param FetchesOrder $fetchesOrder
     * @param CreateOrderProcessor $createOrderProcessor
     * @param FetchesPackingList $fetchesPakcingList
     * @param CreatePackingListProcessor $createPackingListProcessor
     * @param CreatePackageLogic $createPackage
     * @param CreatePackageProcessor $createPackageProcessor
     * @param CreatesTransport $createsTransport
     * @param CreatesSchedule $createsSchedule
     */
    public function __construct(FetchesDataFromVTPortal $fetchesDataFRomVTPortal, CleansOldAddress $cleansOldAddress, CreateAddressFromOldAddressProcessor $createAddressFromOldAddressProcessor, FetchesCompanyModule $fetchesCompanyModule, FetchesOrder $fetchesOrder, CreateOrderProcessor $createOrderProcessor, FetchesPackingList $fetchesPakcingList, CreatePackingListProcessor $createPackingListProcessor, CreatePackageLogic $createPackage, CreatePackageProcessor $createPackageProcessor, CreatesTransport $createsTransport, CreatesSchedule $createsSchedule)
    {
        $this->fetchesDataFRomVTPortal = $fetchesDataFRomVTPortal;
        $this->cleansOldAddress = $cleansOldAddress;
        $this->createAddressFromOldAddressProcessor = $createAddressFromOldAddressProcessor;
        $this->fetchesCompanyModule = $fetchesCompanyModule;
        $this->fetchesOrder = $fetchesOrder;
        $this->createOrderProcessor = $createOrderProcessor;
        $this->fetchesPackingList = $fetchesPakcingList;
        $this->createPackingListProcessor = $createPackingListProcessor;
        $this->createPackage = $createPackage;
        $this->createPackageProcessor = $createPackageProcessor;
        $this->createsTransport = $createsTransport;
        $this->createsSchedule = $createsSchedule;
    }


    /**
     * @param Carbon|null $start
     * @param Carbon|null $end
     * @return array
     * @throws GuzzleException
     */
    public function execute(?Carbon $start = null, ?Carbon $end = null){

        DB::beginTransaction();

        try {

            $start = $start ? $start : Carbon::today()->subDays(10);

            $startLimit = Carbon::parse('11-08-2021');

            if($start->isBefore($startLimit)){
                $start = $startLimit;
            }

            $end = $end ? $end : Carbon::today()->addDay();

            $filter = '["ParcelDate:$between$%js%\"'.$start->format('Y-m-d').'T00:00:00.000\"$and$%js%\"'.$end->format('Y-m-d').'T00:00:00.000\"\u0000"]';

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

            $response = $this->fetchesDataFRomVTPortal->getResponseBody($warehouseListRequest);

            foreach ($response->Rows as $parcel){

                $allow_contract = true;
                $marking = preg_split('(-|\(|\)|\/)', str_replace("/YW","", $parcel[11]));
                $orderNumber = $marking[array_key_last($marking)];

                $quantity = $parcel[16];

                if(!$quantity){
                    continue;
                }

                if(!$parcel[23] || !$parcel[22] || !$parcel[21]) continue;

                try {
                    $order = $this->fetchesOrder->execute(['reference' => $orderNumber]);
                    $appointee_id = $order->orderRoles()->where('role_id', '=', OrderRoleTypes::ORIGIN_FREIGHT_FORWARDER)->first()->appointee->id;
                } catch (ResourceNotFoundException $exception) {
                    $allow_contract = false;
                    $order = $this->fetchesCompanyModule->execute(['id' => 1]);
                    $appointee_id = 2037;
                }

                $packingListReference = $parcel[0];
//                $measurement = round(($parcel[26]/$quantity) ** (1/3) * 100, 2);
                $description = $parcel[13];
                $tracking = $parcel[37];
                $receiveDate = $parcel[1];

                $packingListObject = new PackingListObject($packingListReference, $appointee_id, PackingListType::WAREHOUSE_RECEIVE_LIST, $allow_contract ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED);

                /** @var PackingList $packingList */
                $packingList = $order->packingLists()->where('reference', '=', $packingListReference)->first();

                if(!$packingList) {
                    $packingList = $this->createPackingListProcessor->execute($packingListObject, $order);
                    $transportObject = new TransportObject(TransportType::LAND, null, $tracking, Carbon::parse($receiveDate), Carbon::parse($receiveDate), ApprovalStatus::APPROVED);
                    $this->createsTransport->execute($transportObject, $packingList);
                }

                /** @var Transport $transport */
                $transport = $packingList->transports()->first();

                $transport->schedules()->update(['status' => ApprovalStatus::EXPIRED]);

                $this->createsSchedule->execute($transport, new ScheduleObject(Carbon::parse($receiveDate), Carbon::parse($receiveDate), ApprovalStatus::APPROVED));

                /** @var PackingList $replica */
                $replica = $packingList->packingLists()->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST_REPLICA)->first();
                $packingList->packages()->delete();
                if($replica) $replica->packages()->delete();

                $packageObject = new PackageObject(PackageType::CARTON, $description, $parcel[23], $parcel[22], $parcel[21], 0, $quantity, ApprovalStatus::APPROVED);
                $this->createPackageProcessor->execute($packageObject, $packingList);
            }
        } catch (\Exception $exception){
            Log::error($exception->getMessage());
        }

        DB::commit();
        return [];

    }


}
