<?php

namespace App\Controller;

use App\Entity\Prospect;
use App\Form\ProspectType;
use App\Service\CategoryService;
use App\Service\DataGrid\DataGrid;
use App\Service\DataGrid\DataGridFilterMultiselect;
use App\Service\DataGrid\DataGridFilterQuery;
use App\Service\DataGrid\DataGridFilterRange;
use App\Service\DataGrid\DataGridHeader;
use App\Service\DataGrid\DataGridNavigation;
use App\Service\DataGrid\DataGridSort;
use App\Service\ProspectService;
use App\Tools\DBAL\ProspectStatus;
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\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ProspectController extends FOSRestController
{
    private $service;

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

    /**
     * Retrieves a collection of Prospect resource.
     *
     * @Rest\Get("/prospect/grid")
     * @Rest\View(serializerGroups={"grid"})
     *
     * @param Request         $request
     * @param CategoryService $categoryService
     *
     * @return View
     */
    public function getGridProspectAction(Request $request, CategoryService $categoryService): View
    {
        $dataGrid = new DataGrid();

        $categories = $categoryService->getAllCategories();
        $catArray = array_map(function ($type) { return ['label' => strtoupper($type->getTitle()), 'value' => $type->getId()]; }, $categories);

        $dataGrid
            ->setName('prospect')
            ->addHeader(new DataGridHeader(['label' => 'Status', 'id' => 'status', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Domain', 'id' => 'domain', 'isSortable' => true, 'type' => 'domain']))
            ->addHeader(new DataGridHeader(['label' => 'TF', 'id' => 'domain', 'isSortable' => true, 'type' => 'domain_stats']))
            ->addHeader(new DataGridHeader(['label' => 'DA', 'id' => 'domain', 'isSortable' => true, 'type' => 'domain_stats']))
            ->addHeader(new DataGridHeader(['label' => 'CF', 'id' => 'domain', 'isSortable' => true, 'type' => 'domain_stats']))
            ->addHeader(new DataGridHeader(['label' => 'Name', 'id' => 'name', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Email', 'id' => 'email', 'isSortable' => true, 'type' => 'email']))
            ->addHeader(new DataGridHeader(['label' => 'PayPal Email', 'id' => 'paypalEmail', 'isSortable' => true, 'type' => 'email']))
            ->addHeader(new DataGridHeader(['label' => 'Score', 'id' => 'score', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Links Count', 'id' => 'linksCount', 'isSortable' => true]))
            ->addHeader(new DataGridHeader(['label' => 'Recently Agreed Price', 'id' => 'mostRecentAgreedPrice', '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(
            'status',
            ProspectStatus::all(),
            $request->get('status') ?? ['PRE-QUALIFIED', 'APPROACHED', 'ACTIVE', 'PARTNER']));

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

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

        if ($request->get('TF')) {
            $dataGrid->addFilter(new DataGridFilterRange('TF', [], $request->get('TF')));
        }
        if ($request->get('DA')) {
            $dataGrid->addFilter(new DataGridFilterRange('DA', [], $request->get('DA')));
        }
        if ($request->get('CF')) {
            $dataGrid->addFilter(new DataGridFilterRange('CF', [], $request->get('CF')));
        }
        if ($request->get('score')) {
            $dataGrid->addFilter(new DataGridFilterRange('score', [], $request->get('score')));
        }

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

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


        if (!$dataGrid->getFilters()->containsKey('TF')) {
            $dataGrid->addFilter(new DataGridFilterRange('TF', [], [0, 100]));
        }
        if (!$dataGrid->getFilters()->containsKey('DA')) {
            $dataGrid->addFilter(new DataGridFilterRange('DA', [], [0, 100]));
        }
        if (!$dataGrid->getFilters()->containsKey('CF')) {
            $dataGrid->addFilter(new DataGridFilterRange('CF', [], [0, 100]));
        }
        if (!$dataGrid->getFilters()->containsKey('score')) {
            $dataGrid->addFilter(new DataGridFilterRange('score', [], [0, 100]));
        }

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

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

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

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

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

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

        $form->submit($request->request->all());

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

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

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

    /**
     * Replaces Prospect resource.
     *
     * @Rest\Put("/prospect/{id}")
     *
     * @param Request $request
     * @param int     $id
     *
     * @return View
     */
    public function putProspectAction(Request $request, int $id): View
    {
        try {
            $prospect = $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(ProspectType::class, $prospect, ['csrf_protection' => false]);

        $form->submit($request->request->all());

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

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

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

    /**
     * Updates Prospect resource.
     *
     * @Rest\Patch("/prospect/{id}")
     *
     * @param Request $request
     * @param int     $id
     *
     * @return View
     */
    public function patchProspectAction(Request $request, int $id): View
    {
        try {
            $prospect = $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(ProspectType::class, $prospect, ['csrf_protection' => false]);
        $form->submit($request->request->all(), false);

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

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

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

    /**
     * Removes the Prospect resource.
     *
     * @Rest\Delete("/prospect/{id}")
     *
     * @param int $id
     *
     * @return View
     */
    public function delete(int $id): View
    {
        try {
            $prospect = $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($prospect);

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

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

        $form = $this->createForm(ProspectType::class, $prospect)
            ->remove('score');

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

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