<?php

namespace apexl\Io\modules\component\entities;

use apexl\Io\modules\component\Collections\ComponentCollection;
use apexl\Io\modules\component\Collections\ComponentPropertyCollection;
use apexl\Io\modules\component\Factories\ComponentPropertyFactory;
use apexl\Io\modules\components\Interfaces\ComponentInterface;
use Arrayy\Type\StringCollection;
use JsonSerializable;
use ReflectionClass;

class componentEntity implements JsonSerializable, ComponentInterface
{
    public string $id;
    public string $name;

    public function __construct(
        private ComponentPropertyFactory $propertyFactory,
        public ComponentPropertyCollection $props,
        public ComponentCollection $components,
        protected StringCollection $classes,
    ) {
        $this->ensureName();
        $this->id = sprintf('%s_%s', $this->name, hash('XXH3', microtime()));
    }

    private function ensureName(): void
    {
        if (!isset($this->name)) {
            $this->name = $this->getComponentName();
        }
    }

    public function getComponentName(): string
    {
        return new ReflectionClass($this)->getShortName();
    }

    public function setId(string $id): ComponentEntity
    {
        $this->id = $id;

        return $this;
    }

    public function addProperty(
        string $name,
        mixed $value,
    ): static {
        $this->props->set(
            $name,
            $this->propertyFactory->make($name, $value),
        );

        return $this;
    }

    public function resetClasses(): static
    {
        $this->classes->clear();

        return $this;
    }

    public function addClass(string $class): static
    {
        StringCollection::createFromArray(explode(' ', $class))
            ->map('trim')
            ->filter()
            ->each(fn(string $class) => $this->classes->hasValue($class) || $this->classes->append($class));

        return $this;
    }

    public function removeProperty(string $name): static
    {
        $this->props->clear($name);

        return $this;
    }

    /**
     * Bulk add components
     */
    public function addComponents(array $components): static
    {
        foreach ($components as $component) {
            $this->addComponent($component);
        }

        return $this;
    }

    public function addComponent(componentEntity $componentEntity): static
    {
        $this->components->append($componentEntity);

        return $this;
    }

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

    protected function toArray(): array
    {
        return [
            'name' => $this->name,
            'classes' => $this->classes->toArray(),
            'id' => $this->id,
            'props' => $this->props->toArray(),
            'components' => $this->components
                ->values()
                ->toArray(),
        ];
    }

}
