<?php

namespace TdyGames\Controller\Rest;

use TdyGames\Model\Contest;
use TdyGames\InputFilter\Contest as ContestInputFilter;
use TdyCommons\Controller\BaseRestController;
use TdyGames\Model\Mixture;
use TdyGames\Model\Slot;
use Zend\View\Model\JsonModel;

class ContestsController extends BaseRestController
{
    protected $identifierName = 'id';

    /**
     * @return JsonModel
     */
    public function getList()
    {
        $this->getLogger()->debug('ContestsControllers::getList() start.');

        $q = $this->params()->fromQuery('q', '');
        $p = (int) $this->params()->fromQuery('p', 1);
        $l = (int) $this->params()->fromQuery('l', $this->getSettingsTable()->get('items-per-page'));
        $s = $this->params()->fromQuery('s', []);
        $f = $this->params()->fromQuery('f', []);
        $x = [];

        $isPaginated = $l > 0;

        $resultSet = $this->getContestsTable()->setIndent(self::LOGGER_INDENT)->fetch($q, $x, $f, $s, $isPaginated);
        $resultSet->setCurrentPageNumber((int) $p);
        $resultSet->setItemCountPerPage($l);

        if ($p > 0) {
            $i = (($p - 1) * $l);
        } else {
            $i = 0;
        }

        $contests = iterator_to_array($resultSet, false);

        /**
         * @var int     $k
         * @var Contest $contest
         */
        foreach ($contests as $k => $contest) {
            $contest->setServiceLocator($this->getServiceLocator());
            $contests[$k]->row = ++$i;
            $contests[$k]      = $contest->toStdClass();
        }

        $this->getLogger()->debug('ContestsController::getList() end.');

        return $this->statusOk([
            'entries'    => $contests,
            'pagination' => [
                'pageNumber' => $p,
                'pageSize'   => $l,
                'totalItems' => $resultSet->getTotalItemCount(),
                'totalPages' => $resultSet->count(),
            ],

        ]);
    }

    /**
     * @param int|string $id
     *
     * @return JsonModel
     */
    public function get($id)
    {
        $contest = $this->getContestsTable()->get($id);

        if ($contest) {
            $contest->setServiceLocator($this->getServiceLocator());

            return $this->statusOk([
                'entry'      => $contest->toStdClass(),
                'pagination' => [
                    'pageNumber' => 1,
                    'pageSize'   => 1,
                    'totalItems' => 1,
                    'totalPages' => 1,
                ],
            ]);
        } else {
            return $this->statusNotFound();
        }
    }

    /**
     * @param mixed $data
     *
     * @return JsonModel
     */
    public function create($data)
    {
        $this->getLogger()->debug('ContestsController::create() start.');

        if (!isset($data['action'])) {
            $data['action'] = 'add';
        }

        switch ($data['action']) {
            case 'add':
            default:
                $contest = new Contest($data);
                $contest->createdBy = $this->getCurrentAdmin()->id;

                $contest = $this->getContestsTable()->setIndent(self::LOGGER_INDENT)->save($contest);

                $contest->setServiceLocator($this->getServiceLocator());

                $this->getLogger()->info(self::LOGGER_INDENT . 'Contest ' . $contest->name . ' has been created.');
                $this->getLogger()->debug('ContestsController::create() end.');

                return $this->statusOk([
                    'entry'      => $contest->toStdClass(),
                    'pagination' => [
                        'pageNumber' => 1,
                        'pageSize'   => 1,
                        'totalItems' => 1,
                        'totalPages' => 1,
                    ],
                ]);
                break;
        }

    }

    /**
     * @param int|string $id
     * @param mixed      $data
     *
     * @return JsonModel
     */
    public function update($id, $data)
    {
        if (!isset($data['action'])) {
            $data['action'] = 'edit';
        }

        switch ($data['action']) {
            case 'reset':
                return $this->reset($id);
                break;
            case 'edit':
            default:
                return $this->edit($id, $data);
                break;

        }
    }

    /**
     * @param int|string $id
     *
     * @return JsonModel
     * @throws \Exception
     */
    public function delete($id)
    {
        $this->getLogger()->debug('ContestsController::delete() start.');

        $this->getLogger()->debug(self::LOGGER_INDENT . 'Getting info.');

        if ($id > 0) {
            $contest = $this->getContestsTable()->get($id);
            if ($contest) {

                $this->getLogger()->debug(self::LOGGER_INDENT . 'Contest ID  : ' . $id);
                $this->getLogger()->debug(self::LOGGER_INDENT . 'Contest Name: ' . $contest->name);

                $contest->deletedBy = $this->getCurrentAdmin()->id;
                $this->getContestsTable()->setIndent(self::LOGGER_INDENT)->delete($contest);

                $this->getLogger()->info(self::LOGGER_INDENT . 'Contest ' . $contest->name . ' has been deleted.');
                $this->getLogger()->debug('ContestsController::delete() end.');

                return $this->statusOk([
                    'entry'      => null,
                    'pagination' => [
                        'pageNumber' => 1,
                        'pageSize'   => 1,
                        'totalItems' => 1,
                        'totalPages' => 1,
                    ],
                ]);
            } else {
                $this->getLogger()->debug(self::LOGGER_INDENT . 'Contest ID ' . $id . ' does not exists.');
                $this->getLogger()->debug('ContestsController::delete() end.');

                return $this->statusNotFound();
            }
        } else {
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Contest ID is requred for deletion.');
            $this->getLogger()->debug('ContestsController::delete() end.');

            return $this->statusNotFound();
        }
    }

    /**
     * @param $id
     * @param $data
     *
     * @return JsonModel
     * @throws \Exception
     */
    protected function edit($id, $data)
    {
        $this->getLogger()->debug('ContestsController::edit() start.');

        $data['id'] = (int) $id;

        $inputFilter = new ContestInputFilter($this->getServiceLocator(), true);
        $inputFilter->setData($data);

        if ($inputFilter->isValid()) {
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Input Filter is valid. Continue.');

            $contest            = new Contest($data);
            $contest->updatedBy = $this->getCurrentAdmin()->id;
            $contest            = $this->getContestsTable()->setIndent(self::LOGGER_INDENT)->save($contest);

            $this->getLogger()->info(self::LOGGER_INDENT . 'Contest ' . $contest->name . ' has been updated.');
            $this->getLogger()->debug('ContestsController::update() end.');

            return $this->statusOk([
                'entry'      => $contest->toStdClass(),
                'pagination' => [
                    'pageNumber' => 1,
                    'pageSize'   => 1,
                    'totalItems' => 1,
                    'totalPages' => 1,
                ],
            ]);
        } else {
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Input Filter is invalid. Will not update.');
            $this->getLogger()->debug('ContestsController::update() end.');

            return $this->statusBadRequest([
                'system'    => [
                    'id'          => 4001,
                    'description' => 'Invalid Request'
                ],
                'companies' => [
                    'description' => 'Submission is invalid.',
                    'details'     => $inputFilter->getMessages(),
                ]
            ]);
        }
    }

    protected function reset($id)
    {
        $this->getLogger()->debug('ContestsController::reset() start.');

        $connection = $this->getContestsTable()->getAdapter()->getDriver()->getConnection();

        $connection->beginTransaction();

        try {
            $contest            = $this->getContestsTable()->get($id);
            $contest->updatedBy = $this->getCurrentAdmin()->id;
            $this->getContestsTable()->setIndent(self::LOGGER_INDENT)->reset($contest);

            $slots = iterator_to_array($this->getContestsSlotsTable()->setIndent(self::LOGGER_INDENT)->fetch($contest->id));

            /** @var Slot $slot */
            foreach ($slots as $slot) {
                $slot->deletedBy = $contest->updatedBy;
                $mixtures        = iterator_to_array($this->getContestsMixturesTable()->setIndent(self::LOGGER_INDENT . self::LOGGER_INDENT)->fetch(null, null, $slot->id));

                /** @var Mixture $mixture */
                foreach ($mixtures as $mixture) {
                    $mixture->deletedBy = $contest->updatedBy;
                    $this->getContestsMixturesTable()->setIndent(self::LOGGER_INDENT . self::LOGGER_INDENT)->delete($mixture);
                }
                $this->getContestsSlotsTable()->setIndent(self::LOGGER_INDENT . self::LOGGER_INDENT)->delete($slot);
            }

            $this->getLogger()->debug(self::LOGGER_INDENT . 'Commiting transaction...');
            $connection->commit();
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Transaction committed.');

            $this->getLogger()->info(self::LOGGER_INDENT . 'Contest ' . $contest->name . ' has been reset.');
            $this->getLogger()->debug('ContestsController::reset() end.');

            return $this->statusOk([
                'entry'      => $contest->toStdClass(),
                'pagination' => [
                    'pageNumber' => 1,
                    'pageSize'   => 1,
                    'totalItems' => 1,
                    'totalPages' => 1,
                ],
            ]);
        } catch (\Exception $e) {
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Tossed an Exception grenade: ' . $e->getMessage());
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Rolling back...');
            $connection->rollback();
            $this->getLogger()->debug(self::LOGGER_INDENT . 'Rolled back.');
            $this->getLogger()->debug('ContestsController::reset() end.');

            return $this->statusInternalServerError([ $e->getMessage() ]);
        }

    }


}
