<?php

declare(strict_types=1);

namespace apexl\Io\modules\formbuilder\FormBuilders;

use apexl\Io\enums\HttpMethod;
use apexl\Io\includes\RouteManager;
use apexl\Io\modules\component\Collections\ComponentCollection;
use apexl\Io\modules\component\Factories\GenericComponentFactory;
use apexl\Io\modules\component\Interfaces\ComponentInterface;
use apexl\Io\modules\formbuilder\ComponentFactories\FormComponentFactory;
use apexl\Io\modules\formbuilder\ComponentFactories\FormFieldComponentFactory;
use apexl\Io\modules\formbuilder\Components\FieldsetComponent;
use apexl\Io\modules\formbuilder\Components\Form;
use apexl\Io\modules\formbuilder\Components\FormKitField\FormKitField;

abstract readonly class FormBuilder
{
    protected const HttpMethod METHOD = HttpMethod::POST;

    protected Form $form;

    public function __construct(
        private FormFieldComponentFactory $fieldComponentFactory,
        private GenericComponentFactory $componentFactory,
        protected RouteManager $routeManager,
        FormComponentFactory $formComponentFactory,
        string $formClass = Form::class
    ) {
        $this->form = $formComponentFactory->make($formClass);
    }

    public function build(array $values = []): Form
    {
        $this->form->setValues($values);
        $this->init();

        return $this->form;
    }

    protected function init(): void
    {
        $this->form->setMethod(static::METHOD);
        $this->form->setActionUrl($this->formAction());
        $this->form->addComponents($this->components(new ComponentCollection()));
    }

    abstract protected function formAction(): string;

    abstract protected function components(ComponentCollection $components): ComponentCollection;

    /**
     * @param class-string<FormKitField> $class
     */
    protected function field(string $class, string $fieldName): FormKitField
    {
        return $this->fieldComponentFactory->make($class, $fieldName);
    }

    protected function fieldset(callable $callback, string $legend = ''): FieldsetComponent
    {
        $fieldset = $this->component(FieldsetComponent::class);

        if ($legend) {
            $fieldset->setLegend($legend);
        }

        return $callback($fieldset, $this);

    }

    /**
     * @param class-string<ComponentInterface> $class
     */
    protected function component(string $class, array $initParams = [], array $constructorParams = []): ComponentInterface
    {
        return $this->componentFactory->make($class, $initParams, $constructorParams);
    }

}
