<?php

declare(strict_types=1);

/** Authorable content contract for one registered section renderer. */
final class MyronSectionContract
{
    /**
     * @param list<array<string, mixed>> $fields
     * @param list<array<string, mixed>> $repeaters
     */
    public function __construct(
        public readonly array $fields = [],
        public readonly array $repeaters = [],
    ) {
    }

    /**
     * Per-instance entries replace component defaults by key and may append
     * intentionally instance-specific fields without discarding other defaults.
     *
     * @param list<array<string, mixed>> $fields
     * @param list<array<string, mixed>> $repeaters
     */
    public function withOverrides(array $fields, array $repeaters): self
    {
        return new self(
            self::mergeByKey($this->fields, $fields),
            self::mergeByKey($this->repeaters, $repeaters),
        );
    }

    /** @return list<string> */
    public function authorableKeys(): array
    {
        return array_values(array_filter(array_map(
            static fn (array $field): string => trim((string) ($field['key'] ?? '')),
            array_merge($this->fields, $this->repeaters),
        )));
    }

    /**
     * @param list<array<string, mixed>> $base
     * @param list<array<string, mixed>> $overrides
     * @return list<array<string, mixed>>
     */
    private static function mergeByKey(array $base, array $overrides): array
    {
        $indexed = [];
        foreach ($base as $entry) {
            $key = trim((string) ($entry['key'] ?? ''));
            if ($key !== '') {
                $indexed[$key] = $entry;
            }
        }
        foreach ($overrides as $entry) {
            $key = trim((string) ($entry['key'] ?? ''));
            if ($key !== '') {
                $indexed[$key] = isset($indexed[$key]) ? array_replace($indexed[$key], $entry) : $entry;
            }
        }
        return array_values($indexed);
    }
}
