<?php

namespace App\Classes\Modules\PerfexCRM\Processors;

use App\Classes\Modules\PerfexCRM\Services\ConvertsPerfexCRMLeadToCustomer;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMCustomerProject;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMMilestone;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMTask;
use App\Classes\Modules\PerfexCRM\Services\FetchesPerfexCRMProject;
use App\Classes\Modules\PerfexCRM\Services\FetchesPerfexCRMMilestone;
use App\Classes\Modules\PerfexCRM\Services\FetchesPerfexCRMTask;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMCustomer;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMCustomerContact;
use App\Classes\Modules\PerfexCRM\Services\UpdatesPerfexCRMTask;
use App\Classes\Modules\PerfexCRM\Services\UpdatesPerfexCRMCustomer;
use App\Classes\Modules\PerfexCRM\Services\UpdatesPerfexCRMProject;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\CustomerContactObject;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\UpdatePerfexCRMObject;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\CreateTaskPerfexCRMObject;
use App\Classes\ValueObjects\Constants\PerfexCRMTaskStatus;
use App\Classes\ValueObjects\Constants\PerfexCRMProjectStatus;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Request;

class UpdatePerfexCRMProcessor
{
    /** @var ConvertsPerfexCRMLeadToCustomer */
    private $convertsPerfexCRMLeadToCustomer;

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

    /** @var CreatesPerfexCRMMilestone */
    private $createsPerfexCRMMilestone;

    /** @var CreatesPerfexCRMTask */
    private $createsPerfexCRMTask;

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

    /** @var FetchesPerfexCRMMilestone */
    private $fetchesPerfexCRMMilestone;

    /** @var FetchesPerfexCRMTask */
    private $fetchesPerfexCRMTask;

    /** @var CreatesPerfexCRMCustomer */
    private $createsPerfexCRMCustomer;

    /** @var CreatesPerfexCRMCustomerContact */
    private $createsPerfexCRMCustomerContact;

    /** @var UpdatesPerfexCRMTask */
    private $updatesPerfexCRMTask;

    /** @var UpdatesPerfexCRMCustomer */
    private $updatesPerfexCRMCustomer;

    /** @var UpdatesPerfexCRMProject */
    private $updatesPerfexCRMProject;

    /**
     * @param ConvertsPerfexCRMLeadToCustomer $convertsPerfexCRMLeadToCustomer
     * @param CreatesPerfexCRMCustomerProject $createsPerfexCRMCustomerProject
     * @param CreatesPerfexCRMMilestone $createsPerfexCRMMilestone
     * @param CreatesPerfexCRMTask $createsPerfexCRMTask
     * @param FetchesPerfexCRMProject $fetchesPerfexCRMProject
     * @param FetchesPerfexCRMMilestone $fetchesPerfexCRMMilestone
     * @param FetchesPerfexCRMTask $fetchesPerfexCRMTask
     * @param CreatesPerfexCRMCustomer $createsPerfexCRMCustomer
     * @param CreatesPerfexCRMCustomerContact $createsPerfexCRMCustomerContact
     * @param UpdatesPerfexCRMTask $updatesPerfexCRMTask
     * @param UpdatesPerfexCRMCustomer $updatesPerfexCRMCustomer
     * @param UpdatesPerfexCRMProject $updatesPerfexCRMProject
    */
    public function __construct(ConvertsPerfexCRMLeadToCustomer $convertsPerfexCRMLeadToCustomer,
    CreatesPerfexCRMCustomerProject $createsPerfexCRMCustomerProject,
    CreatesPerfexCRMMilestone $createsPerfexCRMMilestone,
    CreatesPerfexCRMTask $createsPerfexCRMTask,
    FetchesPerfexCRMProject $fetchesPerfexCRMProject,
    FetchesPerfexCRMMilestone $fetchesPerfexCRMMilestone,
    FetchesPerfexCRMTask $fetchesPerfexCRMTask,
    CreatesPerfexCRMCustomer $createsPerfexCRMCustomer,
    CreatesPerfexCRMCustomerContact $createsPerfexCRMCustomerContact,
    UpdatesPerfexCRMTask $updatesPerfexCRMTask,
    UpdatesPerfexCRMCustomer $updatesPerfexCRMCustomer,
    UpdatesPerfexCRMProject $updatesPerfexCRMProject)
   {
        $this->convertsPerfexCRMLeadToCustomer = $convertsPerfexCRMLeadToCustomer;
        $this->createsPerfexCRMCustomerProject = $createsPerfexCRMCustomerProject;
        $this->createsPerfexCRMMilestone = $createsPerfexCRMMilestone;
        $this->createsPerfexCRMTask = $createsPerfexCRMTask;
        $this->fetchesPerfexCRMProject = $fetchesPerfexCRMProject;
        $this->fetchesPerfexCRMMilestone = $fetchesPerfexCRMMilestone;
        $this->fetchesPerfexCRMTask = $fetchesPerfexCRMTask;
        $this->createsPerfexCRMCustomer = $createsPerfexCRMCustomer;
        $this->createsPerfexCRMCustomerContact = $createsPerfexCRMCustomerContact;
        $this->updatesPerfexCRMTask = $updatesPerfexCRMTask;
        $this->updatesPerfexCRMCustomer = $updatesPerfexCRMCustomer;
        $this->updatesPerfexCRMProject = $updatesPerfexCRMProject;
   }

   /**
    * @param UpdatePerfexCRMObject $updatePerfexCRMObject
    * @return null|object
    * @throws \App\Classes\Exceptions\MalformedRequestException
    */
    public function execute(UpdatePerfexCRMObject $updatePerfexCRMObject) {
        $projectId = "";

        // Customer has to exist first before Project can appear under it
        // Check with Perfex CRM, if this user (email) was previously a lead, should automatically now become a customer
        $crmCompany = $updatePerfexCRMObject->getCompanyName();
        $result = $this->convertsPerfexCRMLeadToCustomer->execute($updatePerfexCRMObject->getContactEmail());

        if(isset($result->payload)){
                $crmClientId = $result->payload['client_id'];
                if (isset($result->payload['company'])) {
                    $crmCompany = $result->payload['company'];
                }
        }
        else{
            //if reach this point, this means this user is not a official customer nor is a lead in crm
            //Create Customer has 2 parts: Create Company (client), Create Contact
            $result = $this->createsPerfexCRMCustomer->execute($crmCompany);
            if(is_null($result)){
                    $crmCompany = $crmCompany." 2";
                    $result = $this->createsPerfexCRMCustomer->execute($crmCompany);
                }
            $crmClientId = $result->payload['clientId'];

            $customerContactObject = new CustomerContactObject(
                $crmClientId,
                $updatePerfexCRMObject->getContactName(),
                $updatePerfexCRMObject->getContactName(),
                $updatePerfexCRMObject->getContactEmail(),
                "pU^T@sC#9Q",
                "on",
                "on"
            );
            $result = $this->createsPerfexCRMCustomerContact->execute($customerContactObject);
        }

        //Update custom fields to identify company reference from exchange or shipping portal
        $value_exists = false;
        if (isset($result->payload['customfields'])) {
            foreach ($result->payload['customfields'] as $element) {
                if ($element['value'] === $updatePerfexCRMObject->getCompanyReference()) {
                    $value_exists = true;
                    break;
                }
            }
        }
        if(!$value_exists);
        {
            $result = $this->updatesPerfexCRMCustomer->execute($crmClientId, $crmCompany, $updatePerfexCRMObject->getCompanyReference());
        }

        // Get existing or create project, project has to exist first before milestone can appear under it
        $result = $this->fetchesPerfexCRMProject->execute($updatePerfexCRMObject->getProjectName(), $crmClientId);
        if(isset($result->payload)){
            $project = $result->payload[0];
            $projectId = $project['id'];
            if($updatePerfexCRMObject->getProjectStatus() != PerfexCRMProjectStatus::NOT_STARTED && $project['status'] == PerfexCRMProjectStatus::NOT_STARTED)
            {
                $this->updatesPerfexCRMProject->execute($project, $updatePerfexCRMObject->getProjectStatus());
            }
        }
        else{
            $result = $this->createsPerfexCRMCustomerProject->execute($updatePerfexCRMObject->getProjectName(), $updatePerfexCRMObject->getProjectStatus(), $crmClientId);
            if(isset($result->payload)){  //Here means project creation successful
                $projectId = $result->payload['project_id'];
            }
        }

        $tasks = $updatePerfexCRMObject->getTasks();
        if(count($tasks) > 0){

            //Create tasks with milestone
            for($count=0; $count < count($tasks); $count++) {
                $milestoneId = 0; //By default milestoneId is 0, having this set at individual task is optional
                if($tasks[$count]['milestone'] != "") //Create milestone only if it is defined
                {
                    // Get existing or create milestone, milestone has to exist first before task can appear under it
                    $result = $this->fetchesPerfexCRMMilestone->execute($tasks[$count]['milestone'], $projectId);
                    if(isset($result->payload)){
                        $array = json_decode(json_encode($result->payload[0]), true);
                        $milestoneId = $array['id'];
                    }
                    else{
                        $result = $this->createsPerfexCRMMilestone->execute($tasks[$count]['milestone'], $projectId, $count);
                        if(isset($result->payload)){
                            $milestoneId = $result->payload['milestone_id'];
                        }
                    }
                }

                $taskStatus = PerfexCRMTaskStatus::NOT_STARTED;
                if($tasks[$count]['status'] != ''){
                    $taskStatus = $tasks[$count]['status'];
                }

                // Get existing or create task
                $taskName = $tasks[$count]['name'];
                $taskReference = $tasks[$count]['reference'];
                $taskOnTaskCompletion = $tasks[$count]['on_task_completion'];
                $taskIsAllowMultiple = $tasks[$count]['is_allow_multiple'];
                $taskIsOnTaskCompletionUpdate = $tasks[$count]['is_on_task_completion_update'];
                if($updatePerfexCRMObject->getInvoiceId() != 0 && $taskIsAllowMultiple){
                    $taskName = $taskName." (".$updatePerfexCRMObject->getInvoiceId().")";
                    $taskReference = $taskReference."_".$updatePerfexCRMObject->getInvoiceId();
                    if($taskOnTaskCompletion && $taskIsOnTaskCompletionUpdate){
                        $taskOnTaskCompletion = $taskOnTaskCompletion."_".$updatePerfexCRMObject->getInvoiceId();
                    }
                }

                $result = $this->fetchesPerfexCRMTask->execute($taskName, $milestoneId, 'project', $projectId, $updatePerfexCRMObject->getInvoiceId());
                // Log::error("UpdatePerfexCRMProcessor task: ".$taskName." , ".json_encode($result));
                Log::error("UpdatePerfexCRMProcessor task: ".$taskName);

                if(isset($result->payload)){
                    //&& $result->payload[0]['status'] == PerfexCRMTaskStatus::NOT_STARTED
                    if($taskStatus != PerfexCRMTaskStatus::NOT_STARTED)
                    {
                        $task = $result->payload[0];
                        $result = $this->updatesPerfexCRMTask->execute($task['id'], $task['name'], $task['milestone'], $task['rel_id'], $taskStatus, $task['startdate'], is_null($task['duedate']) ? '': $task['duedate']);
                    }
                }
                else{
                    $createTaskPerfexCRMObject = new CreateTaskPerfexCRMObject(
                        "",
                        $taskName,
                        $tasks[$count]['description'],
                        "",
                        $projectId,
                        $milestoneId,
                        $taskReference,
                        $taskOnTaskCompletion,
                        $taskStatus,
                        $tasks[$count]['department'],
                        $tasks[$count]['priority'],
                        $tasks[$count]['duedate'],
                        $updatePerfexCRMObject->getInvoiceId()
                    );
                    $result = $this->createsPerfexCRMTask->execute($createTaskPerfexCRMObject);
                }
            }
        }

        $payload = [];
        $payload['projectId'] = $projectId;
        return (object) $payload;
    }
}
