<?php

declare(strict_types=1);

abstract class AbstractController
{
    protected string $route;
    protected ApiResponse $response;

    protected string $requestUrl;
    protected ?string $requestBody = null;
    protected ?string $contentType = null;
    protected array $mandatoryAttributes = [];

    public function __construct(string $url)
    {
        $this->requestUrl = $url;
        $this->response = new ApiResponse();
    }

    public function setRequestBody(string $contentType, string $content): void
    {
        $this->requestBody = $content;
        $this->contentType = $contentType;
    }

    public function getResponse(): ApiResponse
    {
        return $this->response;
    }

    public function handle(): void
    {
        if (!$this->validateJsonBody()) {
            $this->response = new ApiJsonResponse(ServerStatus::BAD_REQUEST);
            $this->response->setParameter('success', false);
            $this->response->setMessage('The request body has not the required json attributes!');
        }
    }

    protected function getUrlParam(string $name): ?string
    {
        foreach (explode('/', $this->route) as $index => $fragment) {
            if ($fragment === '{' . $name . '}') {
                return explode('/', $this->requestUrl)[$index];
            }
        }

        return null;
    }

    protected function getUrlParamInt(string $name): ?int
    {
        $param = $this->getUrlParam($name);

        return $param !== null ? (int)$param : null;
    }

    protected function validateJsonBody(): bool
    {
        if (count($this->mandatoryAttributes) === 0) {
            return true;
        }

        if ($this->contentType === MimeType::JSON && $this->requestBody === null) {
            return false;
        }

        try {
            $json = json_decode($this->requestBody);

            foreach ($this->mandatoryAttributes as $attribute) {
                if (!isset($json->{$attribute})) {
                    return false;
                }
            }

            return true;
        } catch (Throwable $e) {
            return false;
        }
    }
}