<?php
// @formatter:off


namespace AutoAdmin\Bundle\Admin\DependencyInjection\Configuration;


use AutoAdmin\Bundle\Admin\Controller\Admin\EntityController;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

class EntityConfiguration implements ConfigurationInterface
{
    public function getConfigTreeBuilder(): TreeBuilder
    {
        $treeBuilder = new TreeBuilder('entities');
        $rootNode = $treeBuilder->getRootNode();
        $rootNode
            ->arrayPrototype()
            ->addDefaultsIfNotSet()
            ->beforeNormalization()
                ->always()
                ->then($this->normalizeCallback())
            ->end()
            ->ignoreExtraKeys(false)// keep additional keys for action_zones for now, TODO: move these zone configs to another node name, to restrict this options potential mess
                ->children()
                    ->scalarNode('name')->end()
                    ->scalarNode('icon')->defaultValue('fa fa-circle')->end()
                    ->scalarNode('slug')->defaultValue(null)->end()
                    ->scalarNode('controller')->defaultValue(EntityController::class)->end()
                    ->scalarNode('class')->defaultValue(null)->end()
                    ->scalarNode('translation_class')->defaultValue(null)->end()
                    ->scalarNode('default_action')->defaultValue(null)->end()
                    ->arrayNode('roles')
                        ->defaultValue([])// will inherit from "global_roles"
                        ->variablePrototype()
                        ->end()
                    ->end()
                    ->append($this->addFormsConfig())
                    ->append($this->addTabsConfig())
                    ->append($this->addActionsConfig())
                    ->append($this->addEntityListConfig())
                    ->append($this->addEntityViewConfig())
                    ->append($this->addEntitySidebarConfig())
                    ->append($this->addEntityTopbarConfig())
                ->end()
            ->end()
        ;

        return $treeBuilder;
    }

    protected function normalizeCallback()
    {
        return function ($v) {
            //            dump('normalizing...');
            //            dump($v);
            if (!empty($v['form']) && is_array($v['form']) && !$this->isNumericlyIndexed($v['form'])) {
                $form = $v['form'];
                foreach ($form as $action => $actionValue) {
                    //                    dump($actionValue);
                    if ($this->isNumericlyIndexed($actionValue)) {
                        $newFormAction = [];
                        foreach ($actionValue as $property) {
                            $newFormAction[$property['admin_tab'] ?? 'default'][] = $property;
                        }
                        $v['form'][$action] = $newFormAction;
                        //                        dump('fixed:');
                        //                        dump($v['form'][$action]);
                    }
                }
            }

            //            dump('normalized:');
            //            dump($v);

            return $v;
        };
    }

    protected function isNumericlyIndexed(array $array)
    {
        return count(array_filter(array_keys($array), 'is_string')) === 0;
    }

    public function addFormsConfig()
    {
        $treeBuilder = new TreeBuilder('form');

        return $treeBuilder->getRootNode()
            ->normalizeKeys(false)
            ->defaultValue([])
            ->arrayPrototype()
                ->info('Forms configuration')
                ->normalizeKeys(false)
                ->arrayPrototype()// > action, ex: "update"
                    ->info('action')
                    ->arrayPrototype()// tab => props[] (tab may be omitted when writing config)
                        ->children()
                            ->scalarNode('property')->isRequired()->end()
                            ->scalarNode('required')->defaultValue(null)->end()
                            ->scalarNode('label')->defaultValue(null)->end()
                            ->scalarNode('type')->defaultValue(null)->end()
                            ->scalarNode('choice_label')->defaultValue(null)->end()
                            ->scalarNode('priority')->defaultValue(null)->end()
                            ->scalarNode('admin_tab')->defaultValue('default')->end()
                            ->scalarNode('if')->defaultValue(null)->end()
                            ->arrayNode('roles')
                                ->scalarPrototype()->end()
                            ->end()
                            ->arrayNode('type_options')
                                ->defaultValue([])
                                ->prototype('variable')->end()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end();
    }

    public function addTabsConfig()
    {
        $treeBuilder = new TreeBuilder('tabs');

        return $treeBuilder->getRootNode()
            ->normalizeKeys(false)
            ->defaultValue([])
            ->arrayPrototype()// > action
                ->arrayPrototype()
                    ->children()
                        ->scalarNode('label')->isRequired()->end()
                        ->scalarNode('icon')->defaultValue('fas fa-image-slash')->end()
                        ->arrayNode('routeParams')
                            ->prototype('variable')->end()
                        ->end()
                    ->end()
                ->end()
            ->end();
    }

    public function addActionsConfig()
    {
        $treeBuilder = new TreeBuilder('actions');

        return $treeBuilder->getRootNode()
            ->defaultValue(ConfigurationDefault::getDefaultActions())
            ->useAttributeAsKey('action', false)
            ->arrayPrototype()
                ->children()
                    ->scalarNode('name')->end()
                    ->scalarNode('type')->defaultValue('default')->end()
                    ->scalarNode('action')->end()
                    // should only be used internally, no in-yaml-config setting
                    ->scalarNode('method')->defaultNull()->end()
                    ->arrayNode('attributes')->variablePrototype()->end()->end()
                    ->scalarNode('attributesString')->defaultValue('')->end()
                    ->scalarNode('buttonColor')->defaultValue('primary')->end()
                    ->scalarNode('classes')->defaultValue('')->end()
                    ->scalarNode('icon')->defaultValue('fa fa-circle')->end()
                    ->scalarNode('route')->defaultValue(null)->end()
                    ->arrayNode('routeParameters')
                        ->defaultValue([])
                        ->prototype('variable')->end()
                    ->end()
                    ->arrayNode('roles')
                        ->defaultValue([])// will inherit from "global_roles" or "entity.x.roles"
                        ->prototype('variable')->end()
                    ->end()
                    ->arrayNode('extra')
                        ->prototype('variable')->end()
                    ->end()
                    // for type = entity_action
                    ->scalarNode('target_entity')->defaultValue(null)->end()
                    ->scalarNode('target_action')->defaultValue(null)->end()
                    ->arrayNode('target_config')
                        ->defaultValue([])
                        ->prototype('variable')->end()
                    ->end()
                    ->arrayNode('routeParamMap')
                        ->info('
permit to define something like:

routeParamMap:
    menuId: property_path:id

in order to use a given object (in a listing action-slot) to feed a parameter
from the parent entity to the child (an id for example)
                        ')
                        ->defaultValue([])
                        ->prototype('variable')->end()
                    ->end()
                    // for type = controller
                    ->scalarNode('target_controller')->defaultValue(null)->end()
                    ->scalarNode('target_method')->defaultValue(null)->end()
                ->end()
            ->end()
        ;
    }

    public function addEntityListConfig()
    {
        $treeBuilder = new TreeBuilder('list');

        return $treeBuilder->getRootNode()
            ->addDefaultsIfNotSet()
            ->children()
                ->arrayNode('fields')
                    ->arrayPrototype()
                        ->children()
                            ->scalarNode('property')->end()
                            ->scalarNode('label')->end()
                            ->scalarNode('sort')->end()
                            ->scalarNode('sort_index')->end()
                        ->end()
                    ->end()
                ->end()
                ->variableNode('topbar')
                    ->defaultValue(null)
                ->end()
                ->variableNode('item_actions')
                    ->defaultValue(null)
                ->end()
                ->variableNode('group_actions')
                    ->defaultValue([])
                ->end()
            ->end()
        ;
    }

    public function addEntityViewConfig()
    {
        $treeBuilder = new TreeBuilder('view');

        return $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('fields')
                    ->arrayPrototype()
                        ->children()
                            ->scalarNode('property')->end()
                            ->scalarNode('label')->end()
                        ->end()
                    ->end()
                ->end()
                ->arrayNode('topbar')
                    ->prototype('variable')->end()
                ->end()
            ->end()
        ;
    }

    public function addEntitySidebarConfig()
    {
        $treeBuilder = new TreeBuilder('sidebar');

        return $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('topbar')
                    ->prototype('variable')->end()
                ->end()
            ->end()
        ;
    }

    public function addEntityTopbarConfig()
    {
        $treeBuilder = new TreeBuilder('topbar');

        return $treeBuilder->getRootNode()
            ->children()
                ->arrayNode('actions')
                    ->prototype('variable')->end()
                ->end()
            ->end()
        ;
    }
}
