<?php

/**
 * Lifestyle Webconsulting GmbH
 *
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is private by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @copyright  2018 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\BackendBundle\Controller;

use Sso\WebserviceBundle\Entity\ServiceProvider\Type\ServiceName;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\FormFactory;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Knp\Component\Pager\Paginator;
use Lexik\Bundle\FormFilterBundle\Filter\FilterBuilderUpdater;
use JMS\DiExtraBundle\Annotation\Inject;
use Sso\WebserviceBundle\Database\Manager as DbManager;
use Sso\BackendBundle\Form;

/**
 * Class ServiceTokenController
 * @package Sso\BackendBundle\Controller
 */
class ServiceTokenController extends WsAbstractController
{
    /**
     * @Inject("form.factory")
     * @var FormFactory
     */
    private $formFactory;

    /**
     * @Inject("lexik_form_filter.query_builder_updater")
     * @var FilterBuilderUpdater
     */
    private $lexikFilterUpdater;

    /**
     * @Inject("knp_paginator")
     * @var Paginator
     */
    private $knpPaginator;

    /**
     * @Inject("service_database_manager")
     * @var DbManager
     */
    private $dbM;

    /**
     * @Route("/", name="_admin_backend_servicetoken_index")
     * @Template()
     */
    public function indexAction(Request $request)
    {
        // initialize a query builder
        $em = $this->get('doctrine.orm.serviceprovider_entity_manager');
        $filterBuilder = $em
            ->getRepository('SsoWebserviceBundle:Type\ServiceName')
            ->createQueryBuilder('a');

        $form = $this->get('form.factory')->create(Form\ServiceNamesFilterType::class);
        $this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $filterBuilder);

        $query = $filterBuilder->getQuery();
        $paginator = $this->get('knp_paginator');
        $pagination = $paginator->paginate($query, $request->query->get('page', 1), 50);

        $addForm = $this->createForm(Form\AddServiceNameType::class, null, [
            'method' => 'POST'
        ]);
        $addForm->handleRequest($request);
        if ($addForm->isSubmitted() && $addForm->isValid()) {
            $addFormData = $addForm->getData();
            $serviceName = new ServiceName();
            $serviceName
                ->setServiceName($addFormData['servicename'])
                ->setServiceActive(1);
            $em->persist($serviceName);
            $em->flush($serviceName);

            $this->addFlash('info', 'Service group added');
            return $this->redirect($this->generateUrl('_admin_backend_servicetoken_index', []));
        }

        return ['form' => $form->createView(), 'pagination' => $pagination, 'addForm' => $addForm->createView()];
    }

    /**
     * @Route("/services/{ServiceNameId}", name="_admin_backend_servicetoken_list_services")
     * @Template()
     */
    public function listServicesAction(Request $request, $ServiceNameId)
    {
        $services = $this->dbM->serviceProvider()->service()->getByServiceNameId($ServiceNameId);
        $notAssignedServices = $this->dbM->serviceProvider()->service()->getNotAssignedByServiceNameId($ServiceNameId);

        $assignableServices = [];
        $assignableServicesCount = 0;
        foreach ($notAssignedServices as $unassignedService) {
            $optionName = '(' . $unassignedService->getServiceType() . ') '
                . $unassignedService->getServiceController() . ' -> ' . $unassignedService->getServiceAction();
            $assignableServices[$unassignedService->getServiceId()] = $optionName;
            $assignableServicesCount++;
        }

        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne($ServiceNameId);

        $form = $this->get('form.factory')->create(Form\ServicesFilterType::class);

        $paginator = $this->get('knp_paginator');
        $pagination = $paginator->paginate($services, $request->query->get('page', 1), 50);

        $assignForm = $this->createForm(Form\AddServiceFilterType::class, null, [
            'method' => 'POST',
            'services' => $assignableServices,
            'servicename' => $serviceName->getServiceName()
        ]);
        $assignForm->handleRequest($request);
        if ($assignForm->isSubmitted() && $assignForm->isValid()) {
            $assignFormData = $assignForm->getData();
            if ($this->dbM->serviceProvider()->service()->addToServiceName($assignFormData['service'],
                $serviceName->getServiceNameId())
            ) {
                $this->addFlash('info', 'Service successfully assigned');
                return $this->redirect($this->generateUrl('_admin_backend_servicetoken_list_services',
                    ['ServiceNameId' => $ServiceNameId]));
            }
        }

        return [
            'form' => $form->createView(),
            'pagination' => $pagination,
            'serviceName' => $serviceName,
            'assignForm' => $assignForm->createView(),
            'assignableServicesCount' => $assignableServicesCount
        ];
    }

    /**
     * @Route("/services/delete/{ServiceId}/{ServiceNameId}", name="_admin_backend_servicetoken_delete_service")
     * @Template()
     */
    public function deleteServiceAction(Request $request, $ServiceId, $ServiceNameId)
    {
        $service = $this->dbM->serviceProvider()->service()->getOneById($ServiceId);
        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne($ServiceNameId);
        $isDeleted = false;

        $form = $this->createForm(Form\DeleteServiceType::class, null, [
            'method' => 'POST',
            'serviceId' => $ServiceId,
            'serviceNameId' => $ServiceNameId
        ]);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $formData = $form->getData();
            if ($this->dbM->serviceProvider()->service()->removeFromServiceName($formData['service'],
                $formData['serviceName'])
            ) {
                $this->addFlash('info', 'Service successfully removed');
                return $this->redirect($this->generateUrl('_admin_backend_servicetoken_list_services',
                    ['ServiceNameId' => $ServiceNameId]));
            }
        }

        return [
            'form' => $form->createView(),
            'service' => $service,
            'serviceName' => $serviceName,
            'serviceNameId' => $ServiceNameId,
            'isDeleted' => $isDeleted
        ];
    }

    /**
     * @Route("/tokens/{ServiceNameId}", name="_admin_backend_servicetoken_list_tokens")
     * @Template()
     */
    public function listTokensAction(Request $request, $ServiceNameId)
    {
        $tokens = $this->dbM->serviceProvider()->token()->getByServiceNameId($ServiceNameId);
        $notAssignedTokens = $this->dbM->serviceProvider()->token()->getNotAssignedByServiceNameId($ServiceNameId);

        $assignableTokens = [];
        $assignableTokenCount = 0;
        foreach ($notAssignedTokens as $unassignedToken) {
            $assignableTokens[$unassignedToken->getServiceToken()] = $unassignedToken->getDescription()
                . ' (' . $this->shortenToken($unassignedToken->getServiceToken()) . ')';
            $assignableTokenCount++;
        }

        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne($ServiceNameId);

        $form = $this->get('form.factory')->create(Form\ServicesFilterType::class);

        $paginator = $this->get('knp_paginator');
        $pagination = $paginator->paginate($tokens, $request->query->get('page', 1), 50);

        $assignForm = $this->createForm(Form\AddTokenType::class, null, [
            'method' => 'POST',
            'tokens' => $assignableTokens,
            'servicename' => $serviceName->getServiceName()
        ]);
        $assignForm->handleRequest($request);
        if ($assignForm->isSubmitted() && $assignForm->isValid()) {
            $assignFormData = $assignForm->getData();
            if ($this->dbM->serviceProvider()->token()->addToServiceName($assignFormData['token'], $ServiceNameId)) {
                $this->addFlash('info', 'Token successfully assigned');
                return $this->redirect($this->generateUrl('_admin_backend_servicetoken_list_tokens',
                    ['ServiceNameId' => $ServiceNameId]));
            }
        }

        return [
            'form' => $form->createView(),
            'pagination' => $pagination,
            'serviceName' => $serviceName,
            'assignForm' => $assignForm->createView(),
            'assignableTokenCount' => $assignableTokenCount
        ];
    }

    /**
     * @Route("/tokens/delete/{ServiceToken}/{ServiceNameId}", name="_admin_backend_servicetoken_delete_token")
     * @Template()
     */
    public function deleteTokenAction(Request $request, $ServiceToken, $ServiceNameId)
    {
        $token = $this->dbM->serviceProvider()->token()->getOneById($ServiceToken);
        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne($ServiceNameId);
        $isDeleted = false;

        $form = $this->createForm(Form\DeleteTokenType::class, null, [
            'method' => 'POST',
            'token' => $ServiceToken,
            'serviceNameId' => $ServiceNameId
        ]);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $formData = $form->getData();
            if ($this->dbM->serviceProvider()->token()->removeFromServiceName($formData['token'],
                $formData['serviceName'])
            ) {
                $this->addFlash('info', 'Token successfully removed');
                return $this->redirect($this->generateUrl('_admin_backend_servicetoken_list_tokens',
                    ['ServiceNameId' => $ServiceNameId]));
            }
        }

        return [
            'form' => $form->createView(),
            'token' => $token,
            'serviceName' => $serviceName,
            'serviceNameId' => $ServiceNameId,
            'isDeleted' => $isDeleted
        ];
    }

    /**
     * @Route("/servicenames/delete/{serviceNameId}", name="_admin_backend_servicetoken_remove_servicename")
     * @Template()
     */
    public function deleteServicenameAction(Request $request, $serviceNameId)
    {
        $em = $this->get('doctrine.orm.serviceprovider_entity_manager');

        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne(
            [
                'ServiceNameId' => $serviceNameId
            ]
        );
        $isDeleted = false;

        $form = $this->createForm(Form\DeleteServiceNameType::class, null, [
            'method' => 'POST',
            'serviceNameId' => $serviceNameId
        ]);
        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            try {
                $em->remove($serviceName);
                $em->flush();
                $isDeleted = true;
                $this->addFlash('info', 'Service group successfully removed');
            } catch (\Exception $exc) {
                $this->addFlash('warning',
                    'Failed to remove service group - make sure no tokens and/or services are connected to it anymore!');
            }

            return $this->redirect($this->generateUrl('_admin_backend_servicetoken_index', []));
        }

        return [
            'form' => $form->createView(),
            'serviceName' => $serviceName,
            'isDeleted' => $isDeleted,
            'countTokens' => count($serviceName->getTokens()),
            'countServices' => count($serviceName->getServices())
        ];
    }

    /**
     * @Route("/servicenames/edit/{serviceNameId}", name="_admin_backend_servicetoken_edit_servicename")
     * @Template()
     */
    public function editServicenameAction(Request $request, $serviceNameId)
    {
        $em = $this->get('doctrine.orm.serviceprovider_entity_manager');
        $serviceName = $this->dbM->serviceProvider()->serviceName()->getOne(
            [
                'ServiceNameId' => $serviceNameId
            ]
        );

        $formData = [
            'servicename' => $serviceName->getServicename(),
            'servicenameid' => $serviceName->getServiceNameId()
        ];
        $form = $this->createForm(Form\EditServiceNameType::class, $formData, [
            'method' => 'POST'
        ]);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $formData = $form->getData();
            $serviceName->setServiceName($formData['servicename']);
            $em->persist($serviceName);
            $em->flush();

            return $this->redirect($this->generateUrl('_admin_backend_servicetoken_index', []));
        }

        return [
            'form' => $form->createView()
        ];
    }


    /**
     * @param string $token
     * @return string
     */
    private function shortenToken($token)
    {
        $tokenLen = strlen($token);
        return substr($token, 0, 10) . '[...]' . substr($token, $tokenLen - 10, 10);
    }
}
