<?php

namespace App\Classes\Modules\PerfexCRM\Processors;

// use App\Classes\Modules\PerfexCRM\DataTransferObjects\ContactObject;

use App\Classes\General\LogHelper;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMInvoice;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMInvoicePayment;
use App\Classes\Modules\PerfexCRM\Services\ConvertsPerfexCRMLeadToCustomer;
use App\Classes\Modules\PerfexCRM\Services\FetchesPerfexCRMProject;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMCustomerProject;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\InvoicePerfexCRMObject;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\InvoicePaymentPerfexCRMObject;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\InvoiceSingleItemPerfexCRMObject;
use App\Classes\ValueObjects\Constants\PerfexCRMProjectStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class CreatePerfexCRMInvoiceProcessor
{

    /** @var CreatesPerfexCRMInvoice */
    private $createsPerfexCRMInvoice;

    /** @var CreatesPerfexCRMInvoicePayment */
    private $createsPerfexCRMInvoicePayment;

    /** @var ConvertsPerfexCRMLeadToCustomer */
    private $convertsPerfexCRMLeadToCustomer;

    /** @var FetchesPerfexCRMProject */
    private $fetchesPerfexCRMProject;

    /** @var CreatesPerfexCRMCustomerProject */
    private $createsPerfexCRMCustomerProject;

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

    /**
     * CreatePerfexCRMInvoiceProcessor constructor.
     * @param CreatesPerfexCRMInvoice $createsPerfexCRMInvoice
     */
    public function __construct(CreatesPerfexCRMInvoice $createsPerfexCRMInvoice,
    CreatesPerfexCRMInvoicePayment $createsPerfexCRMInvoicePayment,
    ConvertsPerfexCRMLeadToCustomer $convertsPerfexCRMLeadToCustomer,
    FetchesPerfexCRMProject $fetchesPerfexCRMProject,
    CreatesPerfexCRMCustomerProject $createsPerfexCRMCustomerProject,
    FetchesCompany $fetchesCompany)
    {
        $this->createsPerfexCRMInvoice = $createsPerfexCRMInvoice;
        $this->createsPerfexCRMInvoicePayment = $createsPerfexCRMInvoicePayment;
        $this->convertsPerfexCRMLeadToCustomer = $convertsPerfexCRMLeadToCustomer;
        $this->fetchesPerfexCRMProject = $fetchesPerfexCRMProject;
        $this->createsPerfexCRMCustomerProject = $createsPerfexCRMCustomerProject;
        $this->fetchesCompany = $fetchesCompany;
    }

    /**
     * @param $transaction
     * @return null|object
     * @throws \App\Classes\Exceptions\MalformedRequestException
     */
    public function execute($transaction) {
        $booking = $transaction->booking;
        $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]);
        $purchaseOrder = $booking->transactions()
            ->where('type', TransactionType::PURCHASE_ORDER)
            ->complete()
            ->first();

        $clientId = "";
        $number = $transaction->bill_no;

        $prefix = "INV-";
        //This will remove the prefix if prefix already exist in the string
        if (substr($number, 0, strlen($prefix)) == $prefix) {
            $number = substr($number, strlen($prefix));
        }

        $number = 'EXC-'.$number;
        $date = Carbon::parse($booking->created_at)->format('Y-m-d');
        $dueDate = Carbon::parse($booking->created_at)->format('Y-m-d');
        $currency = 1;
        $subTotal = 0.00;
        $total = 0.00;

        $billingStreet = "";
        $addresses = $supplier->addresses()->where('billing', '=', true)->first();

        if ($addresses !== null) {
            $billingStreet = $billingStreet.$addresses->street_one;
            $billingStreet = $billingStreet.$addresses->street_two.',';
            $billingStreet = $billingStreet.$addresses->district()->first()->name.',';
            $billingStreet = $billingStreet.$addresses->postcode;
            $billingStreet = $billingStreet.$addresses->state()->first()->name.',';
            $billingStreet = $billingStreet.$addresses->country()->first()->name;
        }
        else{
            $billingStreet = "[Pending Billing Details by user]";
        }

        $allowedPaymentModes = [];
        $invoiceItems = [];

        $firstSupplier = $supplier->employees()->first();
        $email = null;
        if ($firstSupplier) {
            $email = $firstSupplier->email;
            LogHelper::channel('perfex_crm')->info('CreatePerfexCRMInvoiceProcessor debug:'.$email);
        } else {
            $bookingMarking = $transaction->owner->marking;
            $serviceTypeName = $transaction->owner->company->services()->where('id', $transaction->owner->service_id)->first()->name;
            $projectName = 'Exchange | '.$serviceTypeName.' | '.$bookingMarking;
            LogHelper::channel('perfex_crm')->info('$projectName: '.$projectName);
            return $email;
        }

        $result = $this->convertsPerfexCRMLeadToCustomer->execute($email);
        if(isset($result->payload)){
            $clientId = $result->payload['client_id'];
        }

        //get project
        $projectId = "";
        $bookingMarking = $transaction->owner->marking;
        $serviceTypeName = $transaction->owner->company->services()->where('id', $transaction->owner->service_id)->first()->name;
        $projectName = 'Exchange | '.$serviceTypeName.' | '.$bookingMarking;
        $result = $this->fetchesPerfexCRMProject->execute($projectName, $clientId);
        if(isset($result->payload)){
            $project = $result->payload[0];
            $projectId = $project['id'];
        }
        else{
            $result = $this->createsPerfexCRMCustomerProject->execute($projectName, PerfexCRMProjectStatus::NOT_STARTED, $clientId);
            if(isset($result->payload)){  //Here means project creation successful
                $projectId = $result->payload['project_id'];
            }
        }

        if(is_null($purchaseOrder)){
            $extraInvoiceSingleItem = new InvoiceSingleItemPerfexCRMObject(
                'Refer to booking: '.$booking->marking,
                "",
                1.00,
                $transaction->amount,
                1,
                ""
            );
            $subTotal += number_format($transaction->amount, 2,'.','') * 1;
            array_push($invoiceItems, $extraInvoiceSingleItem);
        }
        else{
            foreach ($purchaseOrder->transactionDetails as $key => $transaction_detail){
                $order = $key + 1;
                $stockCode = $transaction_detail->product_code;
                $description = $transaction_detail->product_name;
                $quantity = $transaction_detail->quantity;
                $unitPrice = 0.00;
                if($booking->first()->fix_currency_id !== 1)
                    $unitPrice = (1/$transaction->currency_rate) * $transaction_detail->price;
                else
                    $unitPrice = $transaction_detail->price;

                //$totalAmount = 0.00;
                if($booking->first()->fix_currency_id !== 1){

                    //$totalAmount = (float)number_format( (1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','')*$transaction_detail->quantity;
                    $subTotal += number_format((1/$transaction->currency_rate) * $transaction_detail->price, 2,'.','') * $transaction_detail->quantity;
                }
                else
                {
                    //$totalAmount = (float)number_format($transaction_detail->price, 2,'.','')*$transaction_detail->quantity;
                    $subTotal += number_format($transaction_detail->price, 2,'.','') * $transaction_detail->quantity;
                }

                //string $description, string $longDescription, int $qty, int $rate, int $order, string $unit
                $invoiceSingleItem = new InvoiceSingleItemPerfexCRMObject(
                    $description,
                    "",
                    $quantity,
                    $unitPrice,
                    $order,
                    ""
                );
                array_push($invoiceItems, $invoiceSingleItem);
            }
        }

        //When this transaction is of TransactionType::PAYMENT, the amount is actually in the currecy user choose to pay (RM)
        //So there is no need to convert it
        if ($transaction->type == TransactionType::PAYMENT){
            $total = number_format($transaction->amount, 2,'.','') * 1;
        }
        else{
            if($booking->first()->fix_currency_id !== 1){
                $total = ((1/$transaction->currency_rate) * $transaction->amount) + $transaction->service_charge + $transaction->tax;
            }
            else{
                $total = $transaction->amount + $transaction->service_charge + $transaction->tax;
            }
        }

        //This setting is similar to Setup > Leads > Sources, Setup > Leads > Statuses
        //Can be found at Finance > Payment Modes
        array_push($allowedPaymentModes, 1, 2);

        $invoicePerfexCRMObject = new InvoicePerfexCRMObject(
            $clientId,
            $number,
            $date,
            $dueDate,
            $currency,
            $subTotal,
            $total,
            $billingStreet,
            $projectId,
            $allowedPaymentModes,
            $invoiceItems
        );

        $result = $this->createsPerfexCRMInvoice->execute($invoicePerfexCRMObject);
        return $result;
    }
}

