<?php

namespace App\Controller;

use App\Entity\Content;
use App\Form\ContentType;
use App\Service\Content\TypeService;
use App\Service\ContentService;
use App\Service\DataGrid\DataGrid;
use App\Service\DataGrid\DataGridFilterMultiselect;
use App\Service\DataGrid\DataGridFilterQuery;
use App\Service\DataGrid\DataGridHeader;
use App\Service\DataGrid\DataGridNavigation;
use App\Service\DataGrid\DataGridSort;
use Doctrine\ORM\EntityNotFoundException;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\Annotations\View as ViewAnnotation;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Limenius\Liform\Liform;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Security;

class ContentController extends FOSRestController
{
    private $contentService;
    /**
     * @var TypeService
     */
    private $typeService;

    public function __construct(ContentService $contentService, TypeService $typeService)
    {
        $this->contentService = $contentService;
        $this->typeService = $typeService;
    }

    /**
     * Retrieves a collection of Content resource.
     *
     * @Rest\Get("/content/grid")
     * @Rest\View(serializerGroups={"grid"})
     *
     * @param Request $request
     *
     * @return View
     */
    public function getGridAction(Request $request, Security $security): View
    {
        $dataGrid = new DataGrid();

        $dataGrid
            ->setName('Content')
            ->addHeader(new DataGridHeader(['label' => 'Title', 'id' => 'title', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Campaign', 'id' => 'campaign', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Brief', 'id' => 'brief', 'isSortable' => false]))
            ->addHeader(new DataGridHeader(['label' => 'User', 'id' => 'user', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Due Date', 'id' => 'dueDate', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Status', 'id' => 'status', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Type', 'id' => 'type', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Anchor Href', 'id' => 'anchorHref', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Anchor Text', 'id' => 'anchorText', 'isSortable' => true]));

        $dataGrid->setNavigation(new DataGridNavigation(['page' => $request->get('page'), 'rpp' => $request->get('rpp')]));

        if ($request->get('sort')) {
            $dataGrid->addSorter(new DataGridSort(['sort' => $request->get('sort'), 'order' => $request->get('order')]));
        } else {
            $dataGrid->addSorter(new DataGridSort(['sort' => 'priority', 'order' => 'DESC']));
        }

        $dataGrid->addFilter(new DataGridFilterQuery($request->get('q')));
        $dataGrid->addFilter(new DataGridFilterMultiselect(
            'status',
            [],
            $request->get('status') ?: []));

        $dataGrid->addFilter(new DataGridFilterMultiselect(
            'user',
            [],
            $request->get('user') ?: []));

        if ($security->isGranted(['ROLE_CLIENT_ADMIN', 'ROLE_CLIENT_CONTENT'])) {
            $dataGrid->addFilter(new DataGridFilterMultiselect(
                'campaign',
                [],
                $request->get('campaign') ?: $security->getUser()->getCampaignIds()));
        } else {
            $dataGrid->addFilter(new DataGridFilterMultiselect(
                'campaign',
                [],
                $request->get('campaign') ?: []));
        }
        $dataGrid->addFilter(new DataGridFilterMultiselect(
            'type',
            [],
            $request->get('type') ?: []));

        $dataGrid->addFilter(new DataGridFilterMultiselect(
            'workflow',
            [],
            $request->get('workflow') ?: []));

        $dataGrid->setData($this->contentService->getByGrid($dataGrid))
            ->setTotal($this->contentService->countByGrid($dataGrid));

        // In case our GET was a success we need to return a 200 HTTP OK response with the collection of article object
        return View::create($dataGrid, Response::HTTP_OK);
    }

    /**
     * Retrieves a collection of Content resource.
     *
     * @Rest\Get("/content")
     * @ViewAnnotation(serializerEnableMaxDepthChecks=true)
     *
     * @return View
     */
    public function getAllContents(): View
    {
        $contentVersions = $this->contentService->getAllContents();

        return View::create($contentVersions, Response::HTTP_OK);
    }

    /**
     * Retrieves an contentVersion resource.
     *
     * @Rest\Get("/content/{content}", requirements={"content"="\d+"}))
     *
     * @param int $content
     *
     * @return View|Response
     */
    public function getContent(int $content)
    {
        try {
            $contentVersion = $this->contentService->getContent($content);
            $this->denyAccessUnlessGranted('access', $contentVersion);

            return View::create($contentVersion, Response::HTTP_OK);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_NOT_FOUND, 'message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }
    }

    /**
     * Creates an Content resource.
     *
     * @Rest\Post("/content")
     *
     * @param Request $request
     *
     * @return View
     */
    public function postContent(Request $request): View
    {
        $form = $this->createForm(ContentType::class, null, ['csrf_protection' => false]);
        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {
            $contentVersion = $this->contentService->saveContent($form->getData());

            // In case our POST was a success we need to return a 201 HTTP CREATED response
            return View::create($contentVersion, Response::HTTP_OK);
        }

        // In case our PUT was a success we need to return a 200 HTTP OK response with the object as a result of PUT
        return View::create($form, Response::HTTP_BAD_REQUEST);
    }

    /**
     * Replaces Content resource.
     *
     * @Rest\Put("/content/{content}")
     *
     * @param Request $request
     * @param int     $content
     *
     * @return View
     */
    public function putContent(Request $request, int $content): View
    {
        try {
            $content = $this->contentService->getContent($content);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_NOT_FOUND, 'message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(ContentType::class, $content, ['csrf_protection' => false]);
        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {
            $content = $this->contentService->saveContent($content);

            // In case our POST was a success we need to return a 201 HTTP CREATED response
            return View::create($content, Response::HTTP_OK);
        }

        // In case our PUT was a success we need to return a 200 HTTP OK response with the object as a result of PUT
        return View::create($form, Response::HTTP_BAD_REQUEST);
    }

    /**
     * Updates Content resource.
     *
     * @Rest\Patch("/content/{content}")
     *
     * @param Request $request
     * @param int     $content
     *
     * @return View
     */
    public function patchContentAction(Request $request, int $content): View
    {
        try {
            $contentVersion = $this->contentService->getContent($content);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_NOT_FOUND, 'message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }

        $form = $this->createForm(ContentType::class, $contentVersion);
        $form->submit($request->request->all(), false);

        if ($form->isSubmitted() && $form->isValid()) {
            $contentVersion = $this->contentService->saveContent($form->getData());

            // In case our PUT was a success we need to return a 200 HTTP OK response with the object as a result of PATCH
            return View::create($contentVersion, Response::HTTP_OK);
        }

        // In case our PATCH wasn't a success we need to return a 400 HTTP BAD REQUEST response with the form object as a result
        return View::create($form, Response::HTTP_BAD_REQUEST);
    }

    /**
     * Removes the Content resource.
     *
     * @Rest\Delete("/content/{content}")
     *
     * @param int $content
     *
     * @return View
     */
    public function deleteContent(int $content): View
    {
        try {
            $contentVersion = $this->contentService->getContent($content);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_BAD_REQUEST, 'message' => $e->getMessage()], Response::HTTP_BAD_REQUEST);
        }

        $this->contentService->deleteContent($contentVersion);
        // In case our DELETE was a success we need to return a 204 HTTP NO CONTENT response. The object is deleted.
        return View::create([], Response::HTTP_NO_CONTENT);
    }

    /**
     * Return serialized form to create resource.
     *
     * @Rest\Get("/content/schema")
     *
     * @param Liform $liform
     *
     * @return View
     */
    public function getSchema(Liform $liform): View
    {
        $contentVersion = new Content();

        $form = $this->createForm(ContentType::class, $contentVersion)
            ->remove('wordCount')
            ->remove('priority');

        $form = $liform->transform($form);

        return View::create($form, Response::HTTP_OK);
    }
}
