<?php

declare(strict_types=1);

namespace apexl\Io\modules\formbuilder\Components\FormKitField;

use apexl\Io\modules\component\Collections\ComponentCollection;
use apexl\Io\modules\component\Collections\ComponentPropertyCollection;
use apexl\Io\modules\component\Component\Component;
use apexl\Io\modules\component\Factories\ComponentPropertyFactory;
use apexl\Io\modules\formbuilder\Interfaces\FormComponent;
use apexl\Io\modules\formbuilder\Traits\HasFormIdProperty;
use apexl\Io\modules\validation\Collections\ValidationRuleCollection;
use apexl\Io\modules\validation\Collections\ValidationRuleCollectionCollection;
use apexl\Io\modules\validation\Factories\ValidationRuleFactory;
use apexl\Io\modules\validation\Interfaces\HasValidationRulesInterface;
use apexl\Io\modules\validation\ValidationRules\Required;
use apexl\Io\modules\validation\ValidationRules\ValidationRule;
use Arrayy\Type\StringCollection;

abstract readonly class FormKitField extends Component implements FormComponent, HasValidationRulesInterface
{
    public const string NAME = 'FormKit';

    private const string PROP__ID = 'id';
    private const string PROP__NAME = 'name';
    private const string PROP__TYPE = 'type';
    private const string PROP__LABEL = 'label';
    private const string PROP__DISABLED = 'disabled';
    private const string PROP__LABEL_CLASS = 'label-class';
    private const string PROP__HELP = 'help';
    private const string PROP__VALIDATION = 'validation';
    use HasFormIdProperty;

    protected const string TYPE = self::TYPE;
    protected ValidationRuleCollection $validations;

    public function __construct(
        private ValidationRuleFactory $validationRuleFactory,
        string $fieldName,
        ComponentPropertyFactory $propertyFactory,
        ComponentPropertyCollection $props,
        ComponentCollection $components,
        StringCollection $classes,
    ) {
        parent::__construct(
            $propertyFactory,
            $props,
            $components,
            $classes,
        );

        $this->setName($fieldName);
        $this->setType(static::TYPE);
        $this->validations = new ValidationRuleCollection();
    }

    public function setName(string $fieldName): static
    {
        $this->setProperty(self::PROP__NAME, $fieldName);

        if (!$this->hasProperty(self::PROP__ID)) {
            $this->setId($fieldName);
        }

        return $this;
    }

    public function setId(string $id): static
    {
        return $this->setProperty(self::PROP__ID, $id);
    }

    private function setType(string $type): static
    {
        return $this->setProperty(self::PROP__TYPE, $type);
    }

    public function setLabel(string $label): static
    {
        return $this->setProperty(self::PROP__LABEL, $label);
    }

    public function isRequired(): static
    {
        $this->addValidation(Required::class);

        return $this;
    }

    public function addValidation(ValidationRule|string $validation, array|int|string $config = ''): static
    {
        if (!$validation instanceof ValidationRule) {
            $validation = $this->validationRuleFactory->make(
                $validation,
                $config,
                $this->getProperty(self::PROP__NAME)->value
            );
        }

        $this->validations->set($validation->name, $validation);

        return $this;
    }

    public function isDisabled(bool $isDisabled = true): static
    {
        return $this->setProperty(self::PROP__DISABLED, $isDisabled);
    }

    public function hideLabel(): static
    {
        return $this->setProperty(self::PROP__LABEL_CLASS, 'visually-hidden');
    }

    public function setHelp(string $help): static
    {
        return $this->setProperty(self::PROP__HELP, $help);
    }

    public function toSchema(): array
    {
        $this->setProperty(self::PROP__VALIDATION, $this->validations->toFormKitString());

        return [
            '$formkit' => static::TYPE,
            ...$this->props,
        ];
    }

    public function getValidationRules(ValidationRuleCollectionCollection $rules): ValidationRuleCollectionCollection
    {
        if ($this->validations->isEmpty()) {
            return $rules;
        }

        return ValidationRuleCollectionCollection::createFromArray([
            ...$rules->toArray(),
            ...[
                $this->getProperty(self::PROP__NAME)->value => $this->validations
            ],
        ]);
    }
}
