<?php

declare(strict_types=1);

namespace ComerciaGlobalPayments\AddonPayments\SDK\Request;

use ReflectionClass;
use ReflectionProperty;

/**
 * Class AbstractRequest.
 *
 * Base class for all requests.
 */
abstract class AbstractRequest implements RequestInterface, \JsonSerializable
{
    /**
     * @var string[]
     */
    private $additionalHeaders = [];

    public function addHeader(string $headerName, string $headerValue): RequestInterface
    {
        $this->additionalHeaders[$headerName] = $headerValue;

        return $this;
    }

    /**
     * @return string[]
     */
    public function getAdditionalHeaders(): array
    {
        return $this->additionalHeaders;
    }

    public static function excludedProperties(): array
    {
        return [
            'additionalHeaders',
        ];
    }

    public function serializeSpecialProperties(): array
    {
        return [];
    }

    public function jsonSerialize(): array
    {
        $reflection = new ReflectionClass($this);
        $properties = $reflection->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PROTECTED);
        $data = [];

        foreach ($properties as $property) {
            if (\in_array($property->getName(), static::excludedProperties())) {
                continue;
            }
            $property->setAccessible(true);
            $data[$property->getName()] = $property->getValue($this);
            $property->setAccessible(false);
        }

        return $data;
    }

    public function specialProperties(): array
    {
        $items = $this->serializeSpecialProperties();

        return array_combine(array_keys($items), array_map(function ($key, $callback) {
            return $callback($this->{'get' . ucfirst($key)}());
        }, array_keys($items), $items));
    }

    public function flatArray($array): string
    {
        $innerGlue = ':';
        $innerSeparator = ';';

        return implode($innerSeparator, array_map(static function($key, $value) use ($innerGlue) {
            return "${key}${innerGlue}${value}";
        }, array_keys($array), array_values($array)));
    }
}
