<?php

/**
 * LICENSE: This Software is the property of Lifestyle Webconsulting GmbH (Aschaffenburg, Germany)
 * and is protected 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  2016 Lifestyle Webconsulting GmbH
 * @link       http://www.life-style.de
 */

namespace Sso\BackendBundle\Controller;

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 Sso\ApiBundle\Database\Manager as DbManager;
use Sso\BackendBundle\Form;
use LifeStyle\Tools\CredentialsBundle\Entity\ServiceName;

/**
 * Class ServiceTokenController
 * @package Sso\BackendBundle\Controller
 */
class ServiceTokenController extends WsAbstractController
{
    /**
     * @var FormFactory
     */
    private $formFactory;

    /**
     * @var FilterBuilderUpdater
     */
    private $lexikFilterUpdater;

    /**
     * @var Paginator
     */
    private $knpPaginator;

    /**
     * @var DbManager
     */
    private $dbM;


    public function getServices()
    {
        $this->formFactory = $this->get('form.factory');
        $this->lexikFilterUpdater = $this->get('lexik_form_filter.query_builder_updater');
        $this->knpPaginator = $this->get('knp_paginator');
        $this->dbM = $this->get('service_database_manager');
    }

    /**
     * @Route("/", name="_admin_backend_servicetoken_index")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     * @throws \Doctrine\ORM\OptimisticLockException
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\ORMInvalidArgumentException
     */
    public function indexAction(Request $request)
    {
        $this->getServices();

        // initialize a query builder
        $em = $this->get('doctrine.orm.serviceprovider_entity_manager');
        $filterBuilder = $em
            ->getRepository('LifeStyleToolsCredentialsBundle: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 $this->render(
            '@SsoBackend/service_token/index.html.twig',
            ['form' => $form->createView(), 'pagination' => $pagination, 'addForm' => $addForm->createView()]
        );
    }

    /**
     * @Route("/services/{ServiceNameId}", name="_admin_backend_servicetoken_list_services")
     */
    public function listServicesAction(Request $request, $ServiceNameId)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/list_services.html.twig',
            [
                'form' => $form->createView(),
                'pagination' => $pagination,
                'serviceName' => $serviceName,
                'assignForm' => $assignForm->createView(),
                'assignableServicesCount' => $assignableServicesCount
            ]
        );
    }

    /**
     * @Route("/services/delete/{ServiceId}/{ServiceNameId}", name="_admin_backend_servicetoken_delete_service")
     */
    public function deleteServiceAction(Request $request, $ServiceId, $ServiceNameId)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/delete_service.html.twig',
            [
                'form' => $form->createView(),
                'service' => $service,
                'serviceName' => $serviceName,
                'serviceNameId' => $ServiceNameId,
                'isDeleted' => $isDeleted
            ]
        );
    }

    /**
     * @Route("/tokens/{ServiceNameId}", name="_admin_backend_servicetoken_list_tokens")
     */
    public function listTokensAction(Request $request, $ServiceNameId)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/list_tokens.html.twig',
            [
                '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)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/delete_token.html.twig',
            [
                '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)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/delete_servicename.html.twig',
            [
                '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)
    {
        $this->getServices();

        $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 $this->render(
            '@SsoBackend/service_token/edit_servicename.html.twig',
            [
                '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);
    }
}
