<?php

namespace App\Controller\Campaign;

use App\Entity\Campaign\Schedule;
use App\Form\Campaign\ScheduleType;
use App\Service\Campaign\ScheduleService;
use App\Service\DataGrid\DataGrid;
use App\Service\DataGrid\DataGridFilterDateRange;
use App\Service\DataGrid\DataGridFilterMultiselect;
use App\Service\DataGrid\DataGridHeader;
use App\Service\DataGrid\DataGridNavigation;
use App\Service\DataGrid\DataGridSort;
use App\Tools\DBAL\EnumCampaignScheduleType;
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\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ScheduleController extends FOSRestController
{
    private $service;

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

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

        $dataGrid
            ->setName('Campaign Schedule')
            ->addHeader(new DataGridHeader(['label' => 'Campaign', 'id' => 'campaign', 'isSortable' => true, 'type' => 'campaign']))
            ->addHeader(new DataGridHeader(['label' => 'Type', 'id' => 'type', 'isSortable' => true, 'type' => 'campaign_schedule_type']))
            ->addHeader(new DataGridHeader(['label' => 'Execution TIme', 'id' => 'executionTime', 'isSortable' => true, 'type' => 'datetime']))
            ->addHeader(new DataGridHeader(['label' => 'Output', 'id' => 'output']))
            ->addHeader(new DataGridHeader(['label' => 'Origin', 'id' => 'origin']));

        $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 DataGridFilterMultiselect(
            'campaign',
            [],
            $request->get('campaign') ?? []));

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

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

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

        if (!empty($request->get('executedAt') && 'null' !== $request->get('executedAt'))) {
            list($day, $month, $year) = explode('-', $request->get('executedAt')[0]);
            $start = Chronos::createFromDate((int) $year, (int) $month, (int) $day);
            list($day, $month, $year) = explode('-', $request->get('executedAt')[1]);
            $end = Chronos::createFromDate((int) $year, (int) $month, (int) $day);
            $dataGrid->addFilter(new DataGridFilterDateRange('executedAt', [], [$start, $end]));
        }

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

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

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

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

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

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

    /**
     * Creates an Schedule resource.
     *
     * @Rest\Post("/campaign/schedule")
     *
     * @param Request $request
     *
     * @return View
     */
    public function postAction(Request $request): View
    {
        if ($request->get('batch')) {
            $results = [];
            $total = count($request->get('schedules'));
            $success = 0;
            foreach ($request->get('schedules') as $schedule) {
                $form = $this->createForm(ScheduleType::class, null, ['csrf_protection' => false]);
                $form->submit($schedule);

                if ($form->isSubmitted() && $form->isValid()) {
                    $schedule = $form->getData();
                    $schedule->setType(strtoupper($schedule->getOptions()['type']));
                    $schedule = $this->service->save($schedule);

                    $results[] = ['status' => Response::HTTP_OK, 'response' => $schedule];
                    ++$success;
                } else {
                    $results[] = ['status' => Response::HTTP_BAD_REQUEST, 'result' => $form, 'data' => $schedule];
                }
            }

            return View::create(['total' => $total, 'success' => $success, 'results' => $results], Response::HTTP_OK);
        } else {
            $form = $this->createForm(ScheduleType::class, null);
            $form->submit($request->request->all());

            if ($form->isSubmitted() && $form->isValid()) {
                $schedule = $form->getData();
                $schedule->setType(strtoupper($schedule->getOptions()['type']));
                $schedule = $this->service->save($schedule);

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

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

    /**
     * Replaces Schedule resource.
     *
     * @Rest\Put("/campaign/schedule/{id}")
     *
     * @param Request $request
     * @param int     $id
     *
     * @return View
     */
    public function putAction(Request $request, int $id): View
    {
        try {
            $schedule = $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(ScheduleType::class, $schedule, ['csrf_protection' => false]);
        $form->submit($request->request->all());

        if ($form->isSubmitted() && $form->isValid()) {
            $schedule = $form->getData();
            $schedule->setType(strtoupper($schedule->getOptions()['type']));
            $schedule = $this->service->save($schedule);

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

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

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

        if ($form->isSubmitted() && $form->isValid()) {
            $schedule = $form->getData();
            if ($request->get('options')) {
                $schedule->setType(strtoupper($schedule->getOptions()['type']));
            }
            $schedule = $this->service->save($schedule);

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

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

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

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

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

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

        $form
            ->remove('output')
            ->remove('executedAt');

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

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