<?php

declare(strict_types=1);

namespace CliqThemes\UI\Support\Form;

final class FormSchema
{
    /**
     * Flattens the provided form schema into a list of field definitions with dotted paths.
     *
     * @param array<string,mixed> $schema
     *
     * @return array<int,array<string,mixed>>
     */
    public static function flattenFields(array $schema): array
    {
        $fields = [];

        self::walkContainer($schema, '', null, $fields);

        return $fields;
    }

    /**
     * @param array<string,mixed>                $container
     * @param array<int,array<string,mixed>>     $accumulator
     */
    private static function walkContainer(array $container, string $prefix, ?array $inheritedStorage, array &$accumulator): void
    {
        $fieldSets = [];

        if (isset($container['fields']) && is_array($container['fields'])) {
            $fieldSets[] = $container['fields'];
        }

        foreach (['sections', 'groups'] as $key) {
            if (! isset($container[$key]) || ! is_array($container[$key])) {
                continue;
            }

            foreach ($container[$key] as $nested) {
                if (! is_array($nested)) {
                    continue;
                }

                self::walkContainer($nested, $prefix, $inheritedStorage, $accumulator);
            }
        }

        foreach ($fieldSets as $fields) {
            foreach ($fields as $field) {
                if (! is_array($field)) {
                    continue;
                }

                self::walkField($field, $prefix, $inheritedStorage, $accumulator);
            }
        }
    }

    /**
     * @param array<string,mixed>                $field
     * @param array<int,array<string,mixed>>     $accumulator
     */
    private static function walkField(array $field, string $prefix, ?array $inheritedStorage, array &$accumulator): void
    {
        $name = isset($field['name']) ? (string) $field['name'] : '';

        if ($name === '') {
            return;
        }

        $path = $prefix === '' ? $name : $prefix . '.' . $name;
        $storage = self::normaliseStorage($field['storage'] ?? $inheritedStorage ?? []);

        $accumulator[] = [
            'name' => $name,
            'path' => $path,
            'field' => $field,
            'storage' => $storage,
        ];

        if (! isset($field['fields']) || ! is_array($field['fields'])) {
            return;
        }

        $childStorage = $field['storage'] ?? $storage;

        foreach ($field['fields'] as $child) {
            if (! is_array($child)) {
                continue;
            }

            self::walkField($child, $path, $childStorage, $accumulator);
        }
    }

    /**
     * @param array<string,mixed> $storage
     *
     * @return array<string,mixed>
     */
    private static function normaliseStorage(array $storage): array
    {
        if (! isset($storage['target']) || ! is_string($storage['target']) || $storage['target'] === '') {
            $storage['target'] = 'base';
        }

        return $storage;
    }
}
