<?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\EntInternalMeeting;
use App\Entity\EntInternalMeetingParticipant;
use App\Entity\EntMeetingType;
use App\Entity\EntOperator;
use App\Entity\EntOperatorMeeting;
use App\Entity\EntOperatorMeetingParticipant;
use App\Entity\EntProduction;
use App\Entity\EntProductionMeeting;
use App\Entity\EntProductionMeetingParticipant;
use App\Entity\EntService;
use App\Entity\EntServiceMeeting;
use App\Entity\EntServiceMeetingParticipant;
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_USER")
 */
class InternalMeetingEditController extends AbstractController
{
    /**
     * @Route("/create-internal-meeting", name="create_internal_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function createInternalMeeting(Request $request)
    {
        $internalMeetingClient = json_decode($request->request->get('internalMeeting'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

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

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

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

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

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

        $mappedInternalMeeting = $entInternalMeeting->clientMapper($em, true);
        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_INTERNAL_MEETINGS, ServiceData::ACTION_ADD, $mappedInternalMeeting);
        return Reply::getResponse($mappedInternalMeeting, Message::SUCCESS_INTERNAL_MEETING_CREATE, 0, $serviceData);
    }

    /**
     * @Route("/edit-internal-meeting", name="edit_internal_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function editInternalMeeting(Request $request)
    {
        $internalMeetingClient = json_decode($request->request->get('internalMeeting'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

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

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

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

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

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

        try {
            $entInternalMeeting->setClientData($em, $internalMeetingClient);
            $em->persist($entInternalMeeting);
            $em->flush();

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

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

            /** @var EntInternalMeetingParticipant $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();

        $mappedInternalMeeting = $entInternalMeeting->clientMapper($em, true);
        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_INTERNAL_MEETINGS, ServiceData::ACTION_EDIT, $mappedInternalMeeting);
        return Reply::getResponse($mappedInternalMeeting, Message::SUCCESS_INTERNAL_MEETING_EDIT, 0, $serviceData);
    }

    /**
     * @Route("/delete-internal-meeting", name="delete_internal_meeting")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function deleteInternalMeeting(Request $request)
    {
        $internalMeetingIdClient = json_decode($request->request->get('internalMeetingId'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

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

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

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

        $mappedInternalMeeting = $entInternalMeeting->clientMapper($em, true);
        $em->remove($entInternalMeeting);

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

        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_INTERNAL_MEETINGS, ServiceData::ACTION_DELETE, $mappedInternalMeeting);
        return Reply::getResponse($mappedInternalMeeting, Message::SUCCESS_INTERNAL_MEETING_DELETE, 0, $serviceData);
    }

    /**
     * @Route("/check-internal-meeting-report", name="check_internal_meeting_report")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function checkInternalMeetingReport(Request $request)
    {
        $internalMeetingIdClient = json_decode($request->request->get('internalMeetingId'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();

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

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

    /**
     * @Route("/edit-internal-meeting-report", name="edit_internal_meeting_report")
     * @param Request $request
     * @return JsonResponse
     * @throws \Exception
     */
    public function editInternalMeetingReport(Request $request)
    {
        $internalMeetingIdClient = json_decode($request->request->get('internalMeetingId'));
        $internalMeetingReportClient = json_decode($request->request->get('internalMeetingReport'));
        $em = $this->getDoctrine()->getManager();
        /** @var EntUser $user */
        $user = $this->getUser();


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

        $entInternalMeeting->setReport($internalMeetingReportClient);
        $em->persist($entInternalMeeting);
        $em->flush();

        $mappedInternalMeeting = $entInternalMeeting->clientMapper($em, true);
        $serviceData = new ServiceData();
        $serviceData->addServiceData(ServiceData::SERVICE_DATA_TYPE_INTERNAL_MEETINGS, ServiceData::ACTION_EDIT, $mappedInternalMeeting);
        return Reply::getResponse($mappedInternalMeeting, Message::SUCCESS_INTERNAL_MEETING_REPORT_SET, 0, $serviceData);
    }
}