<?php

namespace App\Service;

use App\Entity\User;
use App\Repository\User\UserRepositoryInterface;
use App\Service\Campaign\LandingPageService;
use App\Service\Campaign\NoticeService;
use App\Service\Campaign\ReportService;
use App\Service\Campaign\Tasklist\TasklistService;
use App\Service\Campaign\Tasklist\TaskService;
use App\Service\DataGrid\DataGridInterface;
use App\Service\User\Factory;
use Doctrine\ORM\EntityNotFoundException;

final class UserService
{
    /**
     * @var UserRepositoryInterface
     */
    private $userRepository;
    /**
     * @var NegotiationService
     */
    private $negotiationService;
    /**
     * @var Factory
     */
    private $factory;
    /**
     * @var ReportService
     */
    private $reportService;
    /**
     * @var TaskService
     */
    private $taskService;
    /**
     * @var ResearchService
     */
    private $researchService;
    /**
     * @var ContentVersionService
     */
    private $contentVersionService;
    /**
     * @var CommentContentService
     */
    private $commentContentService;
    /**
     * @var CommentTaskService
     */
    private $commentTaskService;
    /**
     * @var NoticeService
     */
    private $noticeService;
    /**
     * @var NegotiationMessageService
     */
    private $negotiationMessageService;
    /**
     * @var TasklistService
     */
    private $tasklistService;
    /**
     * @var LandingPageService
     */
    private $landingPageService;
    /**
     * @var CommentLandingPageService
     */
    private $commentLandingPageService;

    /**
     * UserService constructor.
     *
     * @param UserRepositoryInterface   $userRepository
     * @param NegotiationService        $negotiationService
     * @param ReportService             $reportService
     * @param ResearchService           $researchService
     * @param ContentVersionService     $contentVersionService
     * @param CommentContentService     $commentContentService
     * @param CommentTaskService        $commentTaskService
     * @param NoticeService             $noticeService
     * @param NegotiationMessageService $negotiationMessageService
     * @param TasklistService           $tasklistService
     * @param LandingPageService        $landingPageService
     * @param CommentLandingPageService $commentLandingPageService
     */
    public function __construct(UserRepositoryInterface $userRepository, NegotiationService $negotiationService,
                                ReportService $reportService, ResearchService $researchService, ContentVersionService $contentVersionService, CommentContentService $commentContentService,
                                CommentTaskService $commentTaskService, NoticeService $noticeService,
                                NegotiationMessageService $negotiationMessageService, TasklistService $tasklistService, LandingPageService $landingPageService, CommentLandingPageService $commentLandingPageService)
    {
        $this->userRepository = $userRepository;
        $this->negotiationService = $negotiationService;
        $this->reportService = $reportService;
        $this->researchService = $researchService;
        $this->contentVersionService = $contentVersionService;
        $this->commentContentService = $commentContentService;
        $this->commentTaskService = $commentTaskService;
        $this->noticeService = $noticeService;
        $this->negotiationMessageService = $negotiationMessageService;
        $this->tasklistService = $tasklistService;
        $this->landingPageService = $landingPageService;
        $this->commentLandingPageService = $commentLandingPageService;
    }

    public function setUserFactory(Factory $factory)
    {
        $this->factory = $factory;
    }

    public function setTaskService(TaskService $taskService)
    {
        $this->taskService = $taskService;
    }

    /**
     * @param int $userId
     *
     * @return User
     *
     * @throws EntityNotFoundException
     */
    public function getUser(int $userId): User
    {
        $user = $this->userRepository->findById($userId);
        if (!$user) {
            throw new EntityNotFoundException('User with id '.$userId.' does not exist!');
        }

        return $user;
    }

    /**
     * @return array|null
     */
    public function getAllUsers(): ?array
    {
        return $this->userRepository->findAll();
    }

    /**
     * @return array|null
     */
    public function getUsersByGrid(DataGridInterface $dataGrid): ?array
    {
        $criteria = $this->getCriteria($dataGrid);

        return $this->userRepository->findBy(
            $criteria,
            [
                $dataGrid->getSorters()->first()->getSort() => $dataGrid->getSorters()->first()->getOrder(),
            ],
            $dataGrid->getNavigation()->getRpp(),
            $dataGrid->getNavigation()->getRpp() * $dataGrid->getNavigation()->getPage());
    }

    /**
     * @param DataGridInterface $dataGrid
     *
     * @return array
     */
    private function getCriteria(DataGridInterface $dataGrid): array
    {
        $criteria = [];
        if ($dataGrid->getFilters()->containsKey('q') && $dataGrid->getFilters()->get('q')->isValid()) {
            $criteria += ['q' => $dataGrid->getFilters()->get('q')->getValue()];
        }

        if ($dataGrid->getFilters()->containsKey('job_title') && $dataGrid->getFilters()->get('job_title')->isValid()) {
            $criteria += ['jobTitle' => $dataGrid->getFilters()->get('job_title')->getValue()];
        }

        if ($dataGrid->getFilters()->containsKey('campaign') && $dataGrid->getFilters()->get('campaign')->isValid()) {
            $criteria += ['campaign' => $dataGrid->getFilters()->get('campaign')->getValue()];
        }

        if ($dataGrid->getFilters()->containsKey('active') && $dataGrid->getFilters()->get('active')->isValid()) {
            $criteria += ['active' => $dataGrid->getFilters()->get('active')->getValue()];
        }

        return $criteria;
    }

    /**
     * @return int
     */
    public function countUsersByGrid(DataGridInterface $dataGrid): int
    {
        $criteria = $this->getCriteria($dataGrid);

        return $this->userRepository->count($criteria);
    }

    /**
     * @param User $user
     *
     * @return User
     */
    public function saveUser(User $user): User
    {
        $this->userRepository->save($user);

        return $user;
    }

    /**
     * @param User $user
     */
    public function deleteUser(User $user): void
    {
        $this->reassignNegotiationMessages($user);
        $this->reassignNegotiations($user);
        $this->reassignCampaignReports($user);
        $this->reassignTasklist($user);
        $this->reassignTasks($user);
        $this->reassignResearches($user);
        $this->reassignContentVersions($user);
        $this->reassignComments($user);
        $this->reassignCampaignNotices($user);
        $this->reassignLandingPages($user);
        $this->userRepository->delete($user);
    }

    private function reassignNegotiationMessages(User $user)
    {
        $this->negotiationMessageService->moveMessagesBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignNegotiations(User $user)
    {
        $this->negotiationService->moveNegotiationsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignCampaignReports(User $user)
    {
        $this->reportService->moveReportsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignTasklist(User $user)
    {
        $this->tasklistService->moveTasklistsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignTasks(User $user)
    {
        $this->taskService->moveTasksBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignResearches(User $user)
    {
        $this->researchService->moveResearchesBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignContentVersions(User $user)
    {
        $this->contentVersionService->moveVersionsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignComments(User $user)
    {
        $this->commentContentService->moveCommentsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
        $this->commentTaskService->moveCommentsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
        $this->commentLandingPageService->moveCommentsBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignCampaignNotices(User $user)
    {
        $this->noticeService->moveNoticesBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    private function reassignLandingPages(User $user)
    {
        $this->landingPageService->moveLandingPagesBetweenUsers($user->getId(), $this->factory->deletedUser()->getId());
    }

    public function getUserByEmail(string $email)
    {
        return $this->userRepository->findOneBy(['email' => $email]);
    }
}
