<?php

namespace Openguru\OpenCartFramework\Http;

use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\Utils;

final class Request
{
    private $query;
    private $request;
    private $cookies;
    private $files;
    private $server;
    private $content;
    private array $headers = [];

    public function __construct(
        array $query,
        array $request,
        array $cookies,
        array $files,
        array $server,
        array $headers = [],
        string $content = null
    ) {
        $this->query = $query;
        $this->request = $request;
        $this->cookies = $cookies;
        $this->files = $files;
        $this->server = $server;
        $this->headers = $headers;
        $this->content = $content;
    }

    public static function createFromGlobals(): Request
    {
        return new static($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER, getallheaders());
    }

    public function getContent(): string
    {
        if ($this->content === null || $this->content === '') {
            $this->content = (string) file_get_contents('php://input');
        }

        return $this->content;
    }

    public function json(string $key = null, $default = null)
    {
        $content = $this->getContent();

        if (! $content) {
            return $default;
        }

        $decoded = Utils::safeJsonDecode($content);

        if ($key === null) {
            return $decoded;
        }

        return Arr::get($decoded, $key, $default);
    }

    public function get(string $key = null, $default = null)
    {
        if ($key === null) {
            return $this->query;
        }

        return $this->query[$key] ?? $default;
    }

    public function getClientIp(): ?string
    {
        return $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? null;
    }

    public function getUserAgent(): ?string
    {
        return $_SERVER['HTTP_USER_AGENT'] ?? null;
    }

    public function header(string $name): ?string
    {
        $headers = [];
        foreach ($this->headers as $key => $value) {
            $headers[mb_strtolower($key)] = trim($value);
        }

        return $headers[mb_strtolower($name)] ?? null;
    }

    /**
     * @param array|string $key
     * @return bool
     */
    public function has($key): bool
    {
        if (is_array($key)) {
            foreach ($key as $k) {
                if ($this->has($k)) {
                    return true;
                }
            }

            return false;
        }

        if (array_key_exists($key, $this->query)) {
            return true;
        }

        return $this->json($key) !== null;
    }
}
