<?php

namespace kernel;

use Rakit\Validation\Validator;

#[\AllowDynamicProperties]
class Request
{
    /**
     * @var string $host Абсолютный адрес сервера
     */
    public string $host;

    /**
     * @var array $headers Заголовки запроса
     */
    public array $headers;

    /**
     * @var array
     */
    public array $data = [];

    /**
     * @var array
     */
    public array $errors = [];


    public function __construct()
    {
        $this->headers = $this->getRequestHeaders();
        $this->load();
    }


    /**
     * @return array
     */
    public function rules(): array
    {
        return [];
    }

    /**
     * @return array
     */
    public function messages(): array
    {
        return [];
    }

    /**
     * Возвращает абсолютный адрес сервера.
     * @return string
     */
    public function getHost(): string
    {
        if ($this->host !== null) {
            return $this->host;
        }

        $http = $this->getIsSecure() ? 'https' : 'http';

        if ($this->headerExist('Host')) {
            $this->host = $http . '://' . $this->getHeader('Host');
        } elseif (isset($_SERVER['SERVER_NAME'])) {
            $this->host = $http . '://' . $_SERVER['SERVER_NAME'];
        }

        return $this->host;
    }

    /**
     * @return false|array|int|string|null
     */
    public static function getUrlPath(): false|array|int|string|null
    {
        return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    }


    /**
     * Возвращает true если шифрование https, иначе false.
     * @return bool
     */
    public function getIsSecure(): bool
    {
        if (isset($_SERVER['HTTPS']) && (strcasecmp($_SERVER['HTTPS'], 'on') === 0 || $_SERVER['HTTPS'] == 1)) {
            return true;
        }

        return false;
    }


    /**
     * Проверяет был ли передан заголовок запроса.
     * @return bool
     */
    public function headerExist($header): bool
    {
        return isset($this->headers[$header]);
    }


    /**
     * Возвращает заголовок запроса
     * @param string $header Заголовок.
     * @param mixed $defaultValue Значение если, параметр не передан.
     * @return mixed|null
     */
    public function getHeader($header, $defaultValue = null): mixed
    {
        return $this->headers[$header] ?? $defaultValue;
    }


    /**
     * Возвращает GET - параметр.
     * @param string|null $param Параметр.
     * @param mixed|null $defaultValue Значение если, параметр не передан.
     * @return mixed
     */
    public function get(string $param = null, mixed $defaultValue = null): mixed
    {
        if (is_null($param)) {
            return $_GET;
        }

        return $_GET[$param] ?? $defaultValue;
    }


    /**
     * Возвращает POST - параметр.
     * @param string $param Параметр.
     * @param mixed $defaultValue Значение если, параметр не передан.
     * @return mixed
     */
    public function post($param = null, $defaultValue = null): mixed
    {
        if (is_null($param)) {
            return $_POST;
        }

        return $_POST[$param] ?? $defaultValue;
    }


    /**
     * Был ли POST - запрос.
     * @return bool
     */
    public function isPost(): bool
    {
        return ($_SERVER['REQUEST_METHOD'] === 'POST');
    }

    /**
     * Был ли GET - запрос.
     * @return bool
     */
    public function isGet(): bool
    {
        return ($_SERVER['REQUEST_METHOD'] === 'GET');
    }

    /**
     * Загружаем свойсва
     */
    public function load(): void
    {
        if (!empty($_REQUEST)) {
            foreach ($_REQUEST as $key => $item) {
                $this->{$key} = $item;
                $this->data[$key] = $item;
            }
        }
    }

    /**
     * @return bool
     */
    public function validate(): bool
    {
        if (!empty($this->data)) {
            $valid = new Validator();
            $validation = $valid->make($this->data, $this->rules());
            $validation->setMessages($this->messages());
            $validation->validate();
            if ($validation->fails()) {
                $this->errors = $validation->errors();
                return false;
            }
        }

        return true;
    }

    /**
     * @return array
     */
    public function getMessagesArray(): array
    {
        $msgs = [];
        if($this->errors){
            foreach ($this->errors->toArray() as $item){
                $msgs[] = array_values($item)[0];
            }
        }

        return $msgs;
    }

    /**
     * @return array
     */
    protected function getRequestHeaders(): array
    {
        $headers = array();
        foreach ($_SERVER as $key => $value) {
            if (substr($key, 0, 5) <> 'HTTP_') {
                continue;
            }
            $header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
            $headers[$header] = $value;
        }

        return $headers;
    }
}