<?php

namespace App\Classes\Modules\Delivery\ControllersLogic;

use App\Classes\General\Abstracts\AbstractControllerLogic;

use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject;
use App\Classes\Modules\Addresses\Services\CreatesAddress;
use App\Classes\Modules\Addresses\Services\FetchesAddress;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject;
use App\Classes\Modules\Contacts\Processors\CreateContactProcessor;
use App\Classes\Modules\Orders\DataTransferObjects\OrderObject;
use App\Classes\Modules\Orders\Services\CreatesOrder;
use App\Classes\Modules\Orders\Services\GeneratesOrderNumber;
use App\Classes\Modules\Orders\Standards\Rules\CanCreateOrder;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackageObject;
use App\Classes\Modules\PackingLists\DataTransferObjects\PackingListObject;
use App\Classes\Modules\PackingLists\Services\CreatesPackingList;
use App\Classes\Modules\PackingLists\Services\Packages\CreatesPackage;
use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject;
use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\BusinessType;
use App\Classes\ValueObjects\Constants\OrderType;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Http\Resources\DeliveryOrderResource;
use App\Models\Address;
use App\Models\CompanyModule;
use App\Models\Order;
use App\Models\PackingList;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class CreateDeliveryOrderLogic extends AbstractControllerLogic
{

    /**
     * @return array
     */
    protected function notification(): array
    {
        return [
            'title' => 'Created Order',
            'message' => 'You have successfully created a new Order'
        ];
    }

    /** @var FetchesCompany */
    private $fetchesCompany;

    /** @var fetchesAddress */
    private $fetchesAddress;

    /** @var CanCreateOrder */
    private $canCreateOrder;

    /** @var CreatesOrder */
    private $createsOrder;

    /** @var CreatesAddress */
    private $createAddress;

    /** @var CreateContactProcessor */
    private $createContactProcessor;

    /** @var CreateRemarkProcessor */
    private $createRemarkProcessor;

    /** @var GeneratesOrderNumber */
    private $generatesOrderNumber;

    /** @var CreatesPackingList */
    private $createsPackingList;

    /** @var CreatesPackage */
    private $createsPackage;


    /**
     * CreateDeliveryOrderLogic constructor.
     * @param FetchesCompany $fetchesCompany
     * @param FetchesAddress $fetchesAddress
     * @param CanCreateOrder $canCreateOrder
     * @param CreatesOrder $createsOrder
     * @param CreatesAddress $createAddress
     * @param CreateContactProcessor $createContactProcessor
     * @param CreateRemarkProcessor $createRemarkProcessor
     * @param GeneratesOrderNumber $generatesOrderNumber
     * @param CreatesPackingList $createsPackingList
     * @param CreatesPackage $createPackage
     */
    public function __construct(FetchesCompany $fetchesCompany, FetchesAddress $fetchesAddress, CanCreateOrder $canCreateOrder, CreatesOrder $createsOrder, CreatesAddress $createAddress, CreateContactProcessor $createContactProcessor, CreateRemarkProcessor $createRemarkProcessor, GeneratesOrderNumber $generatesOrderNumber, CreatesPackingList $createsPackingList, CreatesPackage $createsPackage)
    {
        $this->fetchesCompany = $fetchesCompany;
        $this->fetchesAddress = $fetchesAddress;
        $this->canCreateOrder = $canCreateOrder;
        $this->createsOrder = $createsOrder;
        $this->createAddress = $createAddress;
        $this->createContactProcessor = $createContactProcessor;
        $this->createRemarkProcessor = $createRemarkProcessor;
        $this->generatesOrderNumber = $generatesOrderNumber;
        $this->createsPackingList = $createsPackingList;
        $this->createsPackage = $createsPackage;
    }

    /**
     * @param Request $request
     * @return JsonResponse
     * @throws \App\Classes\Exceptions\AccessForbiddenException
     * @throws \App\Classes\Exceptions\MalformedRequestException
     * @throws \App\Classes\Exceptions\RequestValidationException
     */
    public function logic(Request $request): JsonResponse
    {
        $company = $this->fetchesCompany->execute(['id' => $request->input('company_id')]);

        $senderAddress = $this->fetchesAddress->execute(['id' => $request->input('sender_address_id')]);
        $deliveryAddress = $this->fetchesAddress->execute(['id' => $request->input('delivery_address_id')]);

        /** @var CompanyModule $companyModule */
        $companyModule = $company->companyModules()->where('type', BusinessType::ONLINE_SELLER)->first();

        $orderObject = new OrderObject($this->generatesOrderNumber->execute('168M', 7), OrderType::LAST_MILE_DELIVERY, ApprovalStatus::APPROVED);

        $this->canCreateOrder->passes($orderObject);

        /** @var Order $order */
        $order = $this->createsOrder->execute($companyModule, $orderObject);

        $senderAddressObject = new AddressObject($senderAddress->street_one, $senderAddress->street_two, $senderAddress->country_id, $senderAddress->state_id, $senderAddress->district_id, $senderAddress->postcode, $senderAddress->type, ApprovalStatus::APPROVED, $senderAddress->reference);
        $deliveryAddressObject = new AddressObject($deliveryAddress->street_one, $deliveryAddress->street_two, $deliveryAddress->country_id, $deliveryAddress->state_id, $deliveryAddress->district_id, $deliveryAddress->postcode, $deliveryAddress->type, ApprovalStatus::APPROVED, $deliveryAddress->reference);

        /** @var Address $orderSenderAddress */
        $orderSenderAddress = $this->createAddress->execute($order, $senderAddressObject);
        /** @var Address $orderDeliveryAddress */
        $orderDeliveryAddress = $this->createAddress->execute($order, $deliveryAddressObject);

        $senderContact = $senderAddress->contacts()->first();
        $deliveryContact = $deliveryAddress->contacts()->first();

        $contactObject = new ContactObject($senderContact->reference, $senderContact->phone, '','');
        $this->createContactProcessor->execute($contactObject, $orderSenderAddress);

        $contactObject = new ContactObject($deliveryContact->reference, $deliveryContact->phone, '','');
        $this->createContactProcessor->execute($contactObject, $orderDeliveryAddress);

        $senderRemark = $senderAddress->remarks()->first();
        $deliveryRemark = $deliveryAddress->remarks()->first();

        if ($senderRemark){
            $remarkObject = new RemarkObject($senderRemark->content, Auth()->user()->id);

            if($remarkObject->getContent()){
                $this->createRemarkProcessor->execute($orderSenderAddress, $remarkObject);
            }
        }

        if ($deliveryRemark){
            $remarkObject = new RemarkObject($deliveryRemark->content, Auth()->user()->id);

            if($remarkObject->getContent()){
                $this->createRemarkProcessor->execute($orderDeliveryAddress, $remarkObject);
            }
        }

        $packingListObject = new PackingListObject($order->reference, $companyModule->id, PackingListType::DELIVERY_PACKING_LIST, ApprovalStatus::PENDING_VERIFICATION);

        /** @var PackingList $packingList */
        $packingList = $this->createsPackingList->execute($packingListObject, $order);

        $packageObject = new PackageObject($request->input('packing_list.type'), $request->input('packing_list.description'), (float) 1, (float) 1, (float) 1, $request->input('packing_list.weight'), (float) $request->input('packing_list.quantity'), ApprovalStatus::APPROVED);
        $this->createsPackage->execute($packageObject, $packingList);

        return $this->resourceResponse(new DeliveryOrderResource($order));

    }
}
