<?php
namespace Helpers\Form;

class AbsFormService
{
    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function switch(string $name, array $option = []) :object
    {
        return (object) ($option + [
            'name' => $name,
            'type' => 'SWITCH',
        ]);
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function simpleText(string $name, int $max, array $option = []) :object
    {
        return (object) (
            ['validator' => array_merge(['max' => $max], $option['validator'] ?? [])]
            + $option
            + [
                'name' => $name,
                'type' => 'TEXT',
            ]
        );
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function simpleInteger(string $name, array $option = []) :object
    {
        return (object) ([
            'name' => $name,
            'type' => 'TEXT',
            'validator' => ['format' => 'integer'],
        ] + $option);
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function simpleFloat(string $name, string $format, array $option = []) :object
    {
        return (object) ($option + [
            'name' => $name,
            'type' => 'FLOAT',
            'format' => $format,
        ]);
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function simpleDate(string $name, array $option = []) :object
    {
        return (object) ($option + [
            'name' => $name,
            'type' => 'DATE',
            'inFormat' => 'Ymd',
            'validator' => [],
        ]);
    }

    /**
     * @param array<mixed> $option
     * @param array<string> $listChoices
     * @return \stdClass
     */
    protected function simpleSelect(string $name, array $listChoices, array $option = []) :object
    {
        return (object) ($option + [
            'name' => $name,
            'type' => 'SELECT',
            'choices' => $listChoices,
        ]);
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function cpostal(string $name, string $countryField = 'CODE_PAYS', array $option = []) :object
    {
        return (object) (
            [
                'validator' =>
                    ($option['validator'] ?? [])
                    + [
                        'max' => 10,
                        'code_postal' => $countryField, // TODO : implement FormExtention
                    ]
            ]
            + $option
            + [
                'name' => $name,
                'type' => 'TEXT',
            ]
        );
    }

    /**
     * @param array<mixed> $option
     * @return \stdClass
     */
    protected function simpleZoom(string $name, string $zoomPath, array $option = []) :object
    {
        return (object) ($option + [
            'name' => $name,
            'type' => 'ZOOM',
            'zoom_path' => $zoomPath,
        ]);
    }

    /**
     * @param array<\stdClass> $subform
     * @param array<mixed> $option
     * @return \stdClass
     */
    public function createGroup(string $name, array $subform, array $option = []) :object
    {
        $group = (object) ([
            'type' => 'GROUP',
            'name' => $name,
            'listChild' => $subform,
        ] + $option);

        return $group;
    }

    /**
     * @param array<\stdClass> $form
     * @return \Generator
     */
    public static function traverseForm(array $form)
    {
        foreach ($form as $input) {
            yield $input;
            if (isset($input->listChild)) {
                yield from self::traverseForm($input->listChild);
            }
            if (isset($input->mapSubform)) {
                foreach ($input->mapSubform as $subform) {
                    yield from self::traverseForm($subform);
                }
            }
        }
    }

    /**
     * Retrieve parents names to obtaint fullname
     * (ex: Toto -> Titi -> Tata turned into Toto[Titi][Tata])
     * Note : in the case of a fake input (like Branch) their depth is ignored
     * @param \stdClass $input
     */
    public static function getFullName(object $input) :string
    {
        // Retrieve parents names to obtaint fullname
        // (ex: Toto -> Titi -> Tata turned into Toto[Titi][Tata])
        $stack = [$input->name];
        $current = $input;
        while (isset($current->parent)) {
            $current = $current->parent;

            // Ignore 'Fake' input
            if ($current->type == 'BRANCH') {
                continue;
            }
            
            $stack[] = $current->name;
        }
        return array_reduce(
            array_reverse($stack),
            function ($carry, $item) {
                return $carry === null ? $item : $carry . '[' . $item . ']';
            }
        ) ?? '';
    }
}
