<?php

namespace App\Controller;

use App\Entity\Link;
use App\Form\LinkType;
use App\Service\DataGrid\DataGrid;
use App\Service\DataGrid\DataGridFilterDateRange;
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 App\Service\LinkService;
use App\Tools\DBAL\EnumLinkStatusType;
use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityNotFoundException;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Limenius\Liform\Liform;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;

class LinkController extends FOSRestController
{
    private $service;

    public function __construct(LinkService $service)
    {
        $this->service = $service;
    }

    /**
     * Retrieves a collection of Link resource.
     *
     * @Rest\Get("/link/grid")
     * @Rest\View(serializerGroups={"grid"})
     *
     * @param Request $request
     *
     * @return View
     *
     * @throws \Exception
     */
    public function getGridAction(Request $request): View
    {
        $dataGrid = new DataGrid();

        $dataGrid
            ->setName('Link')
            ->addHeader(new DataGridHeader(['label' => 'URL', 'id' => 'url', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Status', 'id' => 'status', 'isSortable' => true, 'type' => 'link_status']))
            ->addHeader(new DataGridHeader(['label' => 'Prospect', 'id' => 'prospect', 'isSortable' => true, 'type' => 'prospect']))
            ->addHeader(new DataGridHeader(['label' => 'Prospect IP', 'id' => 'ipFrom', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Target IP', 'id' => 'ipTo', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Content', 'id' => 'content', 'isSortable' => true, 'type' => 'content']))
            ->addHeader(new DataGridHeader(['label' => 'Last Checked', 'id' => 'checkedAt', 'type' => 'datetime', 'isSortable' => true]));

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

        $dataGrid->addSorter(new DataGridSort(['sort' => $request->get('sort'), 'order' => $request->get('order')]));

        $dataGrid->addFilter(new DataGridFilterQuery($request->get('q')));

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

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

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

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

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

        $startDate = !empty($request->get('createdAt')[0]) ? $request->get('createdAt')[0] : $this->service->getFirstCreatedAt();
        $endDate = !empty($request->get('createdAt')[1]) ? $request->get('createdAt')[1] : date('Y-m-d H:i:s', time());
        $startDate = (new \DateTime($startDate))->setTime(0, 0, 0)->format('Y-m-d H:i:s');
        $endDate = (new \DateTime($endDate))->setTime(23, 59, 59)->format('Y-m-d H:i:s');
        $dataGrid->addFilter(new DataGridFilterDateRange('createdAt', [], [$startDate, $endDate]));

        if (!empty($request->get('failedAt'))) {
            $start = Chronos::createFromFormat('Y-m-d H:i:s', $request->get('failedAt')[0]);
            $end = Chronos::createFromFormat('Y-m-d H:i:s', $request->get('failedAt')[1]);
            $dataGrid->addFilter(new DataGridFilterDateRange('failedAt', [], [$start, $end]));
        }

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

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

    /**
     * Retrieves a collection of Link resource.
     *
     * @Rest\Get("/link")
     *
     * @return View
     */
    public function getAllAction(): View
    {
        $items = $this->service->getAll();

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

    /**
     * Retrieves an Link resource.
     *
     * @Rest\Get("/link/{id}", requirements={"id"="\d+"}))
     * @Rest\View(serializerEnableMaxDepthChecks=true)
     *
     * @param int $id
     *
     * @return View
     */
    public function getAction(int $id): View
    {
        try {
            $link = $this->service->get($id);

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

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

        if ($form->isSubmitted() && $form->isValid()) {
            $link = $this->service->save($form->getData());

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

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

    /**
     * Replaces Link resource.
     *
     * @Rest\Put("/link/{id}")
     *
     * @param Request $request
     * @param int     $id
     *
     * @return View
     */
    public function putAction(Request $request, int $id): View
    {
        try {
            $link = $this->service->get($id);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_NOT_FOUND, 'message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }

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

        if ($form->isSubmitted() && $form->isValid()) {
            $link = $this->service->save($form->getData());

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

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

    /**
     * Updates Link resource.
     *
     * @Rest\Patch("/link/{id}")
     *
     * @param Request $request
     * @param int     $id
     *
     * @return View
     */
    public function patchAction(Request $request, int $id): View
    {
        try {
            $link = $this->service->get($id);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_NOT_FOUND, 'message' => $e->getMessage()], Response::HTTP_NOT_FOUND);
        }

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

        if ($form->isSubmitted() && $form->isValid()) {
            $link = $this->service->save($form->getData());

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

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

    /**
     * Removes the Link resource.
     *
     * @Rest\Delete("/link/{id}")
     *
     * @param int $id
     *
     * @return View
     */
    public function deleteAction(int $id): View
    {
        try {
            $link = $this->service->get($id);
        } catch (EntityNotFoundException $e) {
            return View::create(['code' => Response::HTTP_BAD_REQUEST, 'message' => $e->getMessage()], Response::HTTP_BAD_REQUEST);
        }

        $this->service->delete($link);

        return View::create([], Response::HTTP_NO_CONTENT);
    }

    /**
     * Get Link Check.
     *
     * @Rest\Get("/link/check")
     *
     * @param Request         $request
     * @param KernelInterface $kernel
     *
     * @return View
     *
     * @throws \Exception
     */
    public function getCheck(Request $request, KernelInterface $kernel): View
    {
        $linkId = $request->get('id');
        if (null === $linkId) {
            return View::create(['message' => 'You have to provide valid Link ID in id parameter'], Response::HTTP_BAD_REQUEST);
        }
        $application = new Application($kernel);
        $application->setAutoExit(false);

        $input = new ArrayInput([
            'command' => 'crm:link:check',
            'linkId' => $linkId,
        ]);

        $output = new NullOutput();
        $application->run($input, $output);

        return View::create([], Response::HTTP_NO_CONTENT);
    }

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

        $form = $this->createForm(LinkType::class, $link, ['csrf_protection' => false]);

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

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