<?php
/**
 * Normalize Bricks component property definitions.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

use LolaCoreForBricks\Elements\IdGenerator;

/**
 * Validates property types and connections for component writes.
 */
final class ComponentProperties
{
    /**
     * @var string[]
     */
    public const TYPES = [
        'text',
        'textarea',
        'richtext',
        'number',
        'image',
        'select',
        'color',
        'toggle',
        'class',
        'link',
        'checkbox',
        'url',
        'icon',
        'video',
        'date',
    ];

    /**
     * @param mixed $raw
     * @param string[] $existingIds
     * @return array{success: true, properties: array<int, array<string, mixed>>}|array{success: false, message: string, error: string}
     */
    public static function normalize(mixed $raw, array $existingIds = []): array
    {
        if (!is_array($raw)) {
            return [
                'success' => false,
                'message' => 'I need the properties as a list. Which ones should this component expose?',
                'error'   => 'invalid_properties',
            ];
        }

        $ids    = new IdGenerator();
        $taken  = $existingIds;
        $items  = [];

        foreach ($raw as $property) {
            if (!is_array($property)) {
                return [
                    'success' => false,
                    'message' => 'Each property needs a name and a type. I could not read one of them.',
                    'error'   => 'invalid_property',
                ];
            }

            $type = strtolower(trim((string) ($property['type'] ?? 'text')));
            if ($type === '') {
                $type = 'text';
            }
            if (!in_array($type, self::TYPES, true)) {
                return [
                    'success' => false,
                    'message' => 'I do not recognize that property type. Use text, image, select, color, class, or toggle.',
                    'error'   => 'invalid_property_type',
                ];
            }

            $id = (string) ($property['id'] ?? '');
            if ($id === '' || !IdGenerator::isValid($id)) {
                $id = $ids->generate($taken);
            }
            $taken[] = $id;

            $name = trim((string) ($property['name'] ?? $property['label'] ?? ''));
            if ($name === '') {
                return [
                    'success' => false,
                    'message' => 'Each property needs a name. What should people see when they edit an instance?',
                    'error'   => 'missing_property_name',
                ];
            }

            $items[] = [
                'id'          => $id,
                'name'        => $name,
                'label'       => (string) ($property['label'] ?? $name),
                'type'        => $type,
                'default'     => $property['default'] ?? '',
                'connections' => self::normalizeConnections($property['connections'] ?? []),
            ];
        }

        return [
            'success'    => true,
            'properties' => $items,
        ];
    }

    /**
     * @param mixed $raw
     * @return array<string, string[]>
     */
    public static function normalizeConnections(mixed $raw): array
    {
        if (!is_array($raw)) {
            return [];
        }

        $connections = [];
        foreach ($raw as $elementId => $keys) {
            if (is_array($keys) && isset($keys['element_id'])) {
                $elementId = (string) $keys['element_id'];
                $keys      = $keys['settings'] ?? $keys['keys'] ?? [];
            }

            $elementId = (string) $elementId;
            if ($elementId === '') {
                continue;
            }

            $settingKeys = [];
            if (is_string($keys) && $keys !== '') {
                $settingKeys[] = $keys;
            } elseif (is_array($keys)) {
                foreach ($keys as $key) {
                    if (is_string($key) && $key !== '') {
                        $settingKeys[] = $key;
                    }
                }
            }

            if ($settingKeys !== []) {
                $connections[$elementId] = array_values(array_unique($settingKeys));
            }
        }

        return $connections;
    }

    /**
     * @param array<int, array<string, mixed>> $properties
     * @param array<string, mixed> $values
     * @return array<string, mixed>
     */
    public static function filterInstanceValues(array $properties, array $values): array
    {
        $allowed = [];
        foreach ($properties as $property) {
            $id = (string) ($property['id'] ?? '');
            if ($id !== '') {
                $allowed[$id] = true;
            }
        }

        $filtered = [];
        foreach ($values as $id => $value) {
            $id = (string) $id;
            if ($id !== '' && isset($allowed[$id])) {
                $filtered[$id] = $value;
            }
        }

        return $filtered;
    }
}
