<?php

declare(strict_types=1);

namespace App\Support\Governance;

use InvalidArgumentException;

final readonly class RegistryOwnershipDescriptor
{
    /**
     * @param  list<string>  $canonicalNouns
     * @param  list<string>  $allowedConsumers
     */
    public function __construct(
        public string $registryKey,
        public string $boundaryClassification,
        public string $ownerLayer,
        public string $sourceClassOrFile,
        public array $canonicalNouns,
        public array $allowedConsumers,
        public ?string $compatibilityNotes = null,
    ) {
        if (trim($this->registryKey) === '' || trim($this->sourceClassOrFile) === '') {
            throw new InvalidArgumentException('Registry ownership descriptors require a registry key and source reference.');
        }

        if ($this->canonicalNouns === [] || $this->allowedConsumers === []) {
            throw new InvalidArgumentException('Registry ownership descriptors require canonical nouns and allowed consumers.');
        }
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public static function fromArray(array $data): self
    {
        return new self(
            registryKey: (string) ($data['registry_key'] ?? ''),
            boundaryClassification: (string) ($data['boundary_classification'] ?? ''),
            ownerLayer: (string) ($data['owner_layer'] ?? ''),
            sourceClassOrFile: (string) ($data['source_class_or_file'] ?? ''),
            canonicalNouns: self::stringList($data['canonical_nouns'] ?? []),
            allowedConsumers: self::stringList($data['allowed_consumers'] ?? []),
            compatibilityNotes: is_string($data['compatibility_notes'] ?? null)
                ? trim((string) $data['compatibility_notes'])
                : null,
        );
    }

    /**
     * @return array{
     *     registry_key: string,
     *     boundary_classification: string,
     *     owner_layer: string,
     *     source_class_or_file: string,
     *     canonical_nouns: list<string>,
     *     allowed_consumers: list<string>,
     *     compatibility_notes: ?string
     * }
     */
    public function toArray(): array
    {
        return [
            'registry_key' => $this->registryKey,
            'boundary_classification' => $this->boundaryClassification,
            'owner_layer' => $this->ownerLayer,
            'source_class_or_file' => $this->sourceClassOrFile,
            'canonical_nouns' => $this->canonicalNouns,
            'allowed_consumers' => $this->allowedConsumers,
            'compatibility_notes' => $this->compatibilityNotes,
        ];
    }

    /**
     * @param  iterable<mixed>  $values
     * @return list<string>
     */
    private static function stringList(iterable $values): array
    {
        return collect($values)
            ->filter(static fn (mixed $value): bool => is_string($value) && trim($value) !== '')
            ->map(static fn (string $value): string => trim($value))
            ->values()
            ->all();
    }
}