<?php
/**
 * Created by PhpStorm.
 * User: danielknudsen
 * Date: 05.04.18
 * Time: 13:09
 */
namespace App\Controller;

use App\Entity\EntCustomer;
use App\Entity\EntCustomerMeeting;
use App\Entity\EntCustomerMeetingParticipant;
use App\Entity\EntMeetingType;
use App\Entity\EntUser;
use App\EntityVirtual\ServiceData;
use App\Utils\Message;
use App\Utils\Reply;
use App\Utils\Utils;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class MeetingEditController
 * @package App\Controller
 * @IsGranted({"ROLE_ADMIN", "ROLE_SALES"})
 */
class CustomerMeetingEditController extends AbstractController
{
    /**
     * @Route("/create-customer-meeting", name="create_customer_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function createCustomerMeeting(Request $request)
    {
        $customerMeetingClient = json_decode($request->request->get('customerMeeting'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();
        /** @var EntCustomer $entCustomer */
        $entCustomer = $em->getRepository(EntCustomer::class)->find($customerMeetingClient->customer_id);
        if (is_null($entCustomer)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        /** @var EntUser $entOwnerUser */
        $entOwnerUser = $em->getRepository(EntUser::class)->find($customerMeetingClient->owner_user_id);
        if (is_null($entOwnerUser)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        /** @var EntMeetingType $entMeetingType */
        $entMeetingType = $em->getRepository(EntMeetingType::class)->find($customerMeetingClient->meeting_type_id);
        if (is_null($entMeetingType)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        // Database manipulation in transaction
        $dbCon = $this->getDoctrine()->getConnection();
        $dbCon->beginTransaction();

        try {
            /** @var EntCustomerMeeting $entCustomerMeeting */
            $entCustomerMeeting = new EntCustomerMeeting($em, $entCustomer, $user, $entOwnerUser, $entMeetingType, $customerMeetingClient->is_option_meeting,
                $customerMeetingClient->title, $customerMeetingClient->start_date, $customerMeetingClient->end_date);
            $entCustomerMeeting->setClientData($em, $customerMeetingClient);
            $em->persist($entCustomerMeeting);
            $em->flush();
            $cntParticipants = count($customerMeetingClient->v_participants);
            for ($i = 0; $i < $cntParticipants; $i++) {
                /** @var EntUser $participantUser */
                $participantUser = $em->getRepository('App:EntUser')->find($customerMeetingClient->v_participants[$i]->participant_user_id);
                if (is_null($participantUser)) {
                    throw new Exception('invalid participant user');
                }

                /** @var EntCustomerMeetingParticipant $entParticipant */
                $entParticipant = new EntCustomerMeetingParticipant($em, $entCustomerMeeting, $participantUser);
                $em->persist($entParticipant);
            }
            $em->flush();

        } catch (Exception $e) {
            return Reply::getErrorResponse(Message::ERROR_INVALID_DATA);
        }
        // All data stored correctly
        $dbCon->commit();

        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_CUSTOMER_MEETINGS, ServiceData::ACTION_ADD, $entCustomerMeeting->clientMapper($em, true));
        return Reply::getResponse($entCustomer->clientMapper($em, true), Message::SUCCESS_CUSTOMER_MEETING_CREATE, 0, $serviceData);
    }

    /**
     * @Route("/edit-customer-meeting", name="edit_customer_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function editCustomerMeeting(Request $request)
    {
        $customerMeetingClient = json_decode($request->request->get('customerMeeting'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();
        /** @var EntCustomer $entCustomer */
        $entCustomer = $em->getRepository('App:EntCustomer')->find($customerMeetingClient->customer_id);
        if (is_null($entCustomer)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        /** @var EntUser $entOwnerUser */
        $entOwnerUser = $em->getRepository('App:EntUser')->find($customerMeetingClient->owner_user_id);
        if (is_null($entOwnerUser)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        /** @var EntMeetingType $entMeetingType */
        $entMeetingType = $em->getRepository('App:EntMeetingType')->find($customerMeetingClient->meeting_type_id);
        if (is_null($entMeetingType)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        /** @var EntCustomerMeeting $entCustomerMeeting */
        $entCustomerMeeting = $em->getRepository('App:EntCustomerMeeting')->find($customerMeetingClient->id);
        if (is_null($entCustomerMeeting)) {
            return Reply::getErrorResponse(Message::ERROR_NON_EXISTING_DATA);
        }

        if (!$entCustomerMeeting->isEditDeletable()) {
            return Reply::getErrorResponse(Message::ERROR_MEETING_NOT_EDIT_DELETABLE);
        }

        $bHasRightsToEdit =
            $entCustomerMeeting->getCreationUserId() == $user->getId() ||
            $entCustomerMeeting->getOwnerUserId() == $user->getId() ||
            $user->isAdmin();
        if (!$bHasRightsToEdit) {
            return Reply::getErrorResponse(Message::ERROR_NOT_ENOUGH_RIGHTS);
        }

        // Database manipulation in transaction
        $dbCon = $this->getDoctrine()->getConnection();
        $dbCon->beginTransaction();

        try {
            $entCustomerMeeting->setClientData($em, $customerMeetingClient);
            $em->persist($entCustomerMeeting);
            $em->flush();

            $formerParticipantsByUserId = Utils::getSortedObjects('getParticipantUserId',
                                $em->getRepository('App:EntCustomerMeetingParticipant')->findBy(['customer_meeting_id' => $entCustomerMeeting->getId()]));
            $pUserIdsToKeep = [];
            $cntParticipants = count($customerMeetingClient->v_participants);
            for ($i = 0; $i < $cntParticipants; $i++) {
                if (!array_key_exists($customerMeetingClient->v_participants[$i]->participant_user_id, $formerParticipantsByUserId)) {
                    /** @var EntUser $participantUser */
                    $participantUser = $em->getRepository('App:EntUser')->find($customerMeetingClient->v_participants[$i]->participant_user_id);
                    if (is_null($participantUser)) {
                        throw new Exception('invalid participant user');
                    }

                    /** @var EntCustomerMeetingParticipant $entParticipant */
                    $entParticipant = new EntCustomerMeetingParticipant($em, $entCustomerMeeting, $participantUser);
                    $em->persist($entParticipant);
                } else {
                    $pUserIdsToKeep[$customerMeetingClient->v_participants[$i]->participant_user_id] = 1;
                }
            }

            /** @var EntCustomerMeetingParticipant $formerParticipant */
            foreach ($formerParticipantsByUserId as $pUserId => $formerParticipant) {
                if (!array_key_exists($pUserId, $pUserIdsToKeep)) {
                    $em->remove($formerParticipant);
                }
            }
            $em->flush();

        } catch (Exception $e) {
            return Reply::getErrorResponse(Message::ERROR_INVALID_DATA);
        }
        // All data stored correctly
        $dbCon->commit();
        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_CUSTOMER_MEETINGS, ServiceData::ACTION_EDIT, $entCustomerMeeting->clientMapper($em, true));
        return Reply::getResponse($entCustomer->clientMapper($em, true), Message::SUCCESS_CUSTOMER_MEETING_EDIT, 0, $serviceData);
    }

    /**
     * @Route("/delete-customer-meeting", name="delete_customer_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function deleteCustomerMeeting(Request $request)
    {
        $customerMeetingIdClient = json_decode($request->request->get('customerMeetingId'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

        /** @var EntCustomerMeeting $entCustomerMeeting */
        $entCustomerMeeting = $em->getRepository('App:EntCustomerMeeting')->find($customerMeetingIdClient);
        if (is_null($entCustomerMeeting)) {
            return Reply::getErrorResponse(Message::ERROR_NON_EXISTING_DATA);
        }

        $bHasRightsToDelete =
            $entCustomerMeeting->getCreationUserId() == $user->getId() ||
            $entCustomerMeeting->getOwnerUserId() == $user->getId() ||
            $user->isAdmin();
        if (!$bHasRightsToDelete) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        if (!$entCustomerMeeting->isEditDeletable()) {
            return Reply::getErrorResponse(Message::ERROR_MEETING_NOT_EDIT_DELETABLE);
        }

        /** @var EntCustomer $entCustomer */
        $entCustomer = $em->getRepository('App:EntCustomer')->find($entCustomerMeeting->getCustomerId());
        if (is_null($entCustomer)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }
        $mappedCustomerMeeting = $entCustomerMeeting->clientMapper($em, true);
        $em->remove($entCustomerMeeting);

        $participants = $em->getRepository('App:EntCustomerMeetingParticipant')->findBy(['customer_meeting_id' => $entCustomerMeeting->getId()]);
        /** @var EntCustomerMeetingParticipant $participant */
        foreach ($participants as $participant) {
            $em->remove($participant);
        }
        $em->flush();

        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_CUSTOMER_MEETINGS, ServiceData::ACTION_DELETE, $mappedCustomerMeeting);
        return Reply::getResponse($entCustomer->clientMapper($em, true), Message::SUCCESS_CUSTOMER_MEETING_DELETE, 0, $serviceData);
    }

    /**
     * @Route("/check-customer-meeting-report", name="check_customer_meeting_report")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function checkCustomerMeetingReport(Request $request)
    {
        $customerMeetingIdClient = json_decode($request->request->get('customerMeetingId'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

        /** @var EntCustomerMeeting $entCustomerMeeting */
        $entCustomerMeeting = $em->getRepository('App:EntCustomerMeeting')->find($customerMeetingIdClient);
        $bHasRightsToMakeReport =
            $entCustomerMeeting->getCreationUserId() == $user->getId() ||
            $entCustomerMeeting->getOwnerUserId() == $user->getId() ||
            $user->isAdmin();
        if (is_null($entCustomerMeeting) || !$bHasRightsToMakeReport) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        $check = new \DateTime() > $entCustomerMeeting->getStartDate();
        return $check ? Reply::getResponse($check) : Reply::getErrorResponse(Message::ERROR_REPORT_NOT_EDITABLE_YET);
    }

    /**
     * @Route("/edit-customer-meeting-report", name="edit_customer_meeting_report")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function editCustomerMeetingReport(Request $request)
    {
        $customerMeetingIdClient = json_decode($request->request->get('customerMeetingId'));
        $customerMeetingReportClient = json_decode($request->request->get('customerMeetingReport'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();


        /** @var EntCustomerMeeting $entCustomerMeeting */
        $entCustomerMeeting = $em->getRepository('App:EntCustomerMeeting')->find($customerMeetingIdClient);
        $bHasRightsToMakeReport =
            $entCustomerMeeting->getOwnerUserId() == $user->getId() ||
            $user->isAdmin();
        if (is_null($entCustomerMeeting) || !$bHasRightsToMakeReport) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        $entCustomer = $em->getRepository('App:EntCustomer')->find($entCustomerMeeting->getCustomerId());
        if (is_null($entCustomer)) {
            return Reply::getErrorResponse(Message::ERROR_DEFAULT);
        }

        $entCustomerMeeting->setReport($customerMeetingReportClient);
        $em->persist($entCustomerMeeting);
        $em->flush();

        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_CUSTOMER_MEETINGS, ServiceData::ACTION_EDIT, $entCustomerMeeting->clientMapper($em, true));
        return Reply::getResponse($entCustomer->clientMapper($em, true), Message::SUCCESS_CUSTOMER_MEETING_REPORT_SET, 0, $serviceData);
    }
}