<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Definition;

use PpPhp\Core\Platform\DI\Contracts\DefinitionInterface;
use PpPhp\Core\Platform\DI\Exceptions\DefinitionException;
use PpPhp\Core\Platform\DI\Metadata\Lifetime;
use PpPhp\Core\Platform\DI\Metadata\Visibility;

abstract class AbstractDefinition implements DefinitionInterface
{
    protected string $lifetime;
    protected string $visibility = Visibility::PUBLIC;
    protected bool $lazy = false;
    protected array $tags = [];
    protected array $aliases = [];
    protected array $metadata = [];

    public function __construct(protected readonly string $id, string $lifetime = Lifetime::TRANSIENT)
    {
        if ($id === '') {
            throw new DefinitionException('Definition id cannot be empty.');
        }
        if (!Lifetime::valid($lifetime)) {
            throw new DefinitionException('Invalid lifetime: ' . $lifetime);
        }
        $this->lifetime = $lifetime;
    }

    public function id(): string { return $this->id; }
    public function lifetime(): string { return $this->lifetime; }
    public function visibility(): string { return $this->visibility; }
    public function lazy(): bool { return $this->lazy; }
    public function tags(): array { return $this->tags; }
    public function aliases(): array { return $this->aliases; }
    public function metadata(): array { return $this->metadata; }

    public function withLifetime(string $lifetime): static
    {
        if (!Lifetime::valid($lifetime)) {
            throw new DefinitionException('Invalid lifetime: ' . $lifetime);
        }
        $this->lifetime = $lifetime;
        return $this;
    }

    public function withVisibility(string $visibility): static
    {
        if (!Visibility::valid($visibility)) {
            throw new DefinitionException('Invalid visibility: ' . $visibility);
        }
        $this->visibility = $visibility;
        return $this;
    }

    public function withLazy(bool $lazy = true): static { $this->lazy = $lazy; return $this; }
    public function withTag(string $tag, array $attributes = []): static { $this->tags[$tag] = $attributes; return $this; }
    public function withAlias(string $alias): static { $this->aliases[] = $alias; return $this; }
    public function withMetadata(string $key, mixed $value): static { $this->metadata[$key] = $value; return $this; }

    protected function baseArray(): array
    {
        return [
            'id' => $this->id,
            'type' => $this->type(),
            'lifetime' => $this->lifetime,
            'visibility' => $this->visibility,
            'lazy' => $this->lazy,
            'tags' => $this->tags,
            'aliases' => $this->aliases,
            'metadata' => $this->metadata,
        ];
    }
}
