<?php

declare(strict_types=1);

namespace apexl\Io\dto;

use JsonSerializable;

abstract readonly class Dto implements JsonSerializable
{
    public function with(string|array $key, mixed $value = null): static
    {
        $props = $this->toArray();

        if (is_string($key)) {
            $key = [$key => $value];
        }

        foreach ($key as $_key => $value) {
            $props[$_key] = $value;
        }

        return new static(...$props);
    }

    public function toArray(): array
    {
        return array_filter(
            get_object_vars($this),
            fn(string $key): bool => !in_array($key, $this->protect(), true),
            ARRAY_FILTER_USE_KEY
        );
    }

    protected function protect(): array
    {
        return [];
    }

    public function without(string|array $key): static
    {
        $props = array_diff_key($this->toArray(), array_flip((array) $key));

        return new static(...$props);
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}
