<?php

declare(strict_types=1);

namespace Seka\Portal\Modul\Terminy\Entities\Registracia\ValueObjects;

use Illuminate\Contracts\Support\Arrayable;
use JsonSerializable;
use Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject;

/**
 * Class ZoznamZvolenychMoznostiUdalostiValueObject
 *
 * @package Seka\Portal\Modul\Terminy\Entities\Registracia\ValueObjects
 */
final class ZoznamZvolenychMoznostiUdalostiValueObject implements Arrayable, JsonSerializable
{
    /**
     * @var
     */
    private $nazov;

    /**
     * @var
     */
    private $kod;

    /**
     * @var MoznostUdalostiValueObject[]
     */
    private array $moznosti;

    /**
     * @param                                                                                       $nazov
     * @param                                                                                       $kod
     * @param \Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject[] $moznosti
     */
    public function __construct($nazov, $kod, array $moznosti = [])
    {
        $this->nazov = $nazov;
        $this->kod = $kod;
        $this->moznosti = $moznosti;
    }

    /**
     * @param            $nazov
     * @param            $kod
     * @param array|null $moznosti
     *
     * @return self
     */
    public static function fromJSON($nazov, $kod, ?array $moznosti): self
    {
        return new self($nazov, $kod, self::makeMoznosti($moznosti));
    }

    /**
     * @param array|null $moznosti
     *
     * @return array
     */
    private static function makeMoznosti(?array $moznosti): array
    {
        if (!is_array($moznosti)) return [];

        return collect($moznosti)->map(function ($moznost) {
            return MoznostUdalostiValueObject::fromJSON($moznost);
        })->all();
    }

    /**
     * @return mixed
     */
    public function getNazov(): string
    {
        return $this->nazov;
    }

    /**
     * @return mixed
     */
    public function getKod(): string
    {
        return $this->kod;
    }

    /**
     * @return \Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject[]
     */
    public function getMoznosti(): array
    {
        return $this->moznosti;
    }

    /**
     * @param \Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject $moznostUdalosti
     *
     * @return self
     */
    public function addMoznost(MoznostUdalostiValueObject $moznostUdalosti): self
    {
        return new self($this->nazov, $this->kod, array_merge_recursive($this->moznosti, [$moznostUdalosti]));
    }

    /**
     * @param \Seka\Portal\Modul\Terminy\Entities\Udalost\ValueObjects\MoznostUdalostiValueObject $moznostUdalosti
     *
     * @return self
     */
    public function removeMoznost(MoznostUdalostiValueObject $moznostUdalosti): self
    {
        $moznosti = array_filter($this->moznosti, function (MoznostUdalostiValueObject $moznost) use ($moznostUdalosti) {
            return !$moznost->isEqual($moznostUdalosti);
        });

        return new self($this->nazov, $this->kod, $moznosti);
    }

    /**
     * @return array
     */
    public function toArray(): array
    {
        return [
            'nazov' => $this->nazov,
            'kod' => $this->kod,
            'moznosti' => array_map(function (MoznostUdalostiValueObject $moznostUdalostiValueObject) {
                return $moznostUdalostiValueObject->toArray();
            }, $this->moznosti),
        ];
    }

    /**
     * @return false|string
     */
    public function jsonSerialize(): bool|string
    {
        return json_encode($this->toArray());
    }
}
