<?php

namespace TdyCommons\Controller;

use Zend\Http\Response as HttpResponse;
use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\View\Model\JsonModel;

/**
 * Class BaseApiController
 * @package TdyCommons\Controller
 *
 * @author  James Lloyd Atwil <james@nadows.com>
 */
class BaseRestController extends AbstractRestfulController
{
    use BaseControllerTrait;

    const LOGGER_INDENT = '   ';

    /**
     * @return HttpResponse
     */
    public function getRequest()
    {
        return parent::getRequest();
    }

    /**
     * @return HttpResponse
     */
    public function getResponse()
    {
        return parent::getResponse();
    }

    /**
     * @return ServiceLocatorInterface
     */
    public function getServiceLocator()
    {
        return parent::getServiceLocator();
    }

    /**
     * Returns HTTP 200 OK
     *
     * @param $data
     *
     * @return JsonModel
     */
    protected function statusOk($data)
    {
        $this->getResponse()->setStatusCode(200);

        return new JsonModel([
            'response' => [
                'status' => [
                    'http' => [
                        'id' => 200,
                        'description' => 'OK',
                        'code' => '200 OK',
                    ],
                    'system' => [
                        'id' => 0,
                        'description' => 'Success'
                    ]
                ],
                'data' => $data,
            ],
        ]);
    }

    /**
     * Respond with HTTP 501 Not Implemented.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusInternalServerError($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 500,
                'description' => 'Internal Server Error',
                'code' => '500 Internal Server Error',
            ],
        ];

        if (is_array($messages) && count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            if (is_string($messages)) {
                $status = array_merge($baseStatus, [$messages]);
            } else {
                $status = $baseStatus;
            }
        }

        $this->getResponse()->setStatusCode(500);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 501 Not Implemented.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusNotImplemented($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 501,
                'description' => 'Method Not Implemented',
                'code' => '501 OK',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(501);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 401 Unauthorized.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusUnauthorized($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 401,
                'description' => 'Unauthorized',
                'code' => '401 Unauthorized',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(401);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 403 Forbidden.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusForbidden($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 403,
                'description' => 'Forbidden',
                'code' => '403 Forbidden',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(403);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 405 Method Not Allowed.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusMethodNotAllowed($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 405,
                'description' => 'Method Not Allowed',
                'code' => '405 Method Not Allowed',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(405);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 400 Bad Request.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusBadRequest($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 400,
                'description' => 'Bad Request',
                'code' => '400 Bad Request',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(400);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond with HTTP 404 Not Found.
     *
     * @param array $messages
     *
     * @return JsonModel
     */
    protected function statusNotFound($messages = [])
    {
        $baseStatus = [
            'http' => [
                'id' => 404,
                'description' => 'Not Found',
                'code' => '404 Not Found',
            ],
        ];

        if (count($messages) > 0) {
            $status = array_merge($baseStatus, $messages);
        } else {
            $status = $baseStatus;
        }

        $this->getResponse()->setStatusCode(404);

        return new JsonModel([
            'response' => [
                'status' => $status,
                'data' => null,
            ],
        ]);
    }

    /**
     * Respond CORS request.
     *
     * @param array $resource
     * @param array $collection
     *
     * @return \Zend\Stdlib\ResponseInterface
     */
    protected function corsRequest($resource = ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'], $collection = ['GET', 'POST'])
    {
        if ($this->params()->fromRoute($this->identifierName, false)) {
            $options = array_merge($resource, ['OPTIONS']);
        } else {
            $options = array_merge($collection, ['OPTIONS']);
        }

        $response = $this->getResponse();
        $response->getHeaders()
            ->addHeaderLine('Content-Type', 'application/json')
            ->addHeaderLine('Access-Control-Allow-Origin', '*')
            ->addHeaderLine('Access-Control-Allow-Headers', 'Accept, Authorization, Origin, Content-Type, X-Requested-With, X-AEV-API-Key, X-AEV-User-Token')
            ->addHeaderLine('Access-Control-Allow-Methods', implode(', ', $options))
            ->addHeaderLine('Allow', implode(', ', $options));

        $jsonModel = $this->statusOk(['allow' => $options]);
        $response->setContent($jsonModel->serialize());

        return $response;
    }

    /**
     * Respond OPTIONS HTTP method.
     *
     * @return HttpResponse
     */
    public function options()
    {
        return $this->corsRequest();
    }

    /**
     * Respond GET HTTP method as collection.
     *
     * @return JsonModel
     */
    public function getList()
    {
        return $this->statusMethodNotAllowed();
    }

    /**
     * Respond GET HTTP method as resource.
     *
     * @param int|string $id
     *
     * @return JsonModel
     */
    public function get($id)
    {
        return $this->statusMethodNotAllowed();
    }

    /**
     * Respond POST HTTP method
     *
     * @param mixed $data
     *
     * @return JsonModel
     */
    public function create($data)
    {
        return $this->statusMethodNotAllowed();
    }

    /**
     * Respond PUT HTTP method
     *
     * @param int|string $id
     * @param mixed      $data
     *
     * @return JsonModel
     */
    public function update($id, $data)
    {
        return $this->statusMethodNotAllowed();
    }

    /**
     * Respond DELETE HTTP method.
     *
     * @param int|string $id
     *
     * @return JsonModel
     */
    public function delete($id)
    {
        return $this->statusMethodNotAllowed();
    }

}
