<?php

namespace apexl\Io\modules\display\includes;

use apexl\entityCore\interfaces\entityInterface;
use apexl\Io\includes\Routes;
use apexl\Io\modules\formbuilder\entities\formEntity;
use apexl\Io\modules\formbuilder\includes\checkboxField;
use apexl\Io\modules\formbuilder\includes\dropzoneField;
use apexl\Io\modules\formbuilder\includes\inputField;
use apexl\Io\modules\formbuilder\includes\numberField;
use apexl\Io\modules\formbuilder\includes\textareaField;

class Forms
{
    public static function fileUploadForm($fileSavePath = 'files.core.upload')
    {
        $form = new formEntity();
        $form->setId('fileUpload');
        $form->setMethod('post');
        $form->setActionUrl(Routes::getRoutePattern($fileSavePath));
        $form->addClass("fileUpload");
        $form->addField((new dropzoneField('upload'))->setLabel('Drop a file here to upload')->setFileSavePath(Routes::getRoutePattern($fileSavePath)));

        return $form;
    }

    /**
     * Provides a standard confirmation form to delete an entity
     * @param $actionUrl
     * @param string $submit
     * @return formEntity|false
     */
    public static function entityActionButtonForm($actionUrl, $submit = 'Confirm Delete')
    {
        $form = new formEntity();
        $form->setId('entityDelete');
        $form->setMethod('post');
        $form->setActionUrl($actionUrl);
        $form->setSubmitText($submit);
        return $form;
    }

    /**
     * @param entityInterface $entity
     * @param array $args
     * @param array $omitColumns
     * @return formEntity
     */
    public static function entityForm(EntityInterface $entity, $args = [], $omitColumns=[])
    {
        $action = 'post';
        if ($id = $args[$entity->primaryKey] ?? false) {
            $entity->load($id);
            //append the ID to the URL, make sure we're consistent so strip any trailing slashes
            $action = 'put';
        }

        $form = self::initiateEntityForm($action, $entity);

        //construct fields
        $fields = [];
        if ($entity->extends && isset($entity->extends->entity)) { // If entity is an extension, add fields of parent
            $parentEntityName = $entity->extends->entity;
            $parentEntity = new $parentEntityName();
            $fields = array_merge($fields, self::entityFormFields($parentEntity, $entity, $omitColumns));
        }
        $fields = array_merge($fields, self::entityFormFields($entity, null, $omitColumns));
        $fields = array_filter($fields);
        foreach ($fields as $field) {
            $form->addField($field);
        }

        return $form;
    }

    /**
     * @param $action
     * @param entityInterface $entity
     * @return formEntity
     */
    public static function initiateEntityForm($action, EntityInterface $entity)
    {
        //form setup
        $replacements = [];
        if ($entity->id ?? false) {
            $replacements[$entity->primaryKey] = $entity->{$entity->primaryKey};
        }
        $form = new formEntity();
        $form->setId('entityForm-'.$entity->getEntityName());
        $form->setMethod($action);
        $form->setActionUrl(Routes::getRoutePattern($entity->getEntityName().'.'.$action, $replacements));
        $form->addClass('entityForm')->addClass($entity->getEntityName());

        return $form;
    }

    public static function entityFormFields(EntityInterface $entity, $childEntity=null, $omitColumns=[])
    {
        $fields = [];
        $entityFields = $entity->getTableColumns();
        foreach ($entityFields as $entityField) {
            //skip the primary key field
            if ($entityField->Field == $entity->primaryKey || in_array($entityField->Field, $omitColumns)) {
                continue;
            }
            //first, split the type into type and length
            $type = $entityField->Type;
            $length = null;
            if (strpos($type, '(')) {
                //i dont like regex, so we're going to cheat. @todo - actually to this with regex
                $parts = explode('(', $type);
                //take the first part as the type
                $type = array_shift($parts);
                //take the second part as the length, strip the end bracket.
                $length = str_replace(')', '', array_shift($parts));
            }
            //don't include any create or modified fields.
            if (in_array($entityField->Field, ["created", "created_by", "modified", "modified_by"])) {
                continue;
            }

            $childEntity = $childEntity ? $childEntity : $entity;
            $fieldConfig = $childEntity->getFieldConfig();

            $fields[$entityField->Field] = self::fieldByType($entityField->Field, $type, $length, $childEntity, $fieldConfig);
        }

        return $fields;
    }

    /**
     * Common field types, these can be overridden later if needed (for example, select options)
     * @param $name
     * @param $type
     * @param $length
     * @param $entity
     * @param bool $disabled
     * @return checkboxField|inputField|textareaField|null
     */
    public static function fieldByType($name, $type, $length, $entity, $fieldConfig, $disabled = false)
    {
        $field = null;
        //allow entity config to override field types.
        if (isset($fieldConfig[$name]) && isset($fieldConfig[$name]['formField'])) {
            $field = $fieldConfig[$name]['formField']($entity);
        } else {
            switch ($type) {
                //not a boolean field? cascade into varchar
                case "int":
                    $field = (new numberField($name))->setLabel($entity->hrName($name))->addClass($name)->setLength($length)->setValue(0);
                    break;
                case "varchar":
                    $field = (new inputField($name))->setLabel($entity->hrName($name))->addClass($name)->setLength($length);
                    break;
                case "text":
                    $field = (new textareaField($name))->setLabel($entity->hrName($name))->addClass($name);
                    break;
                case 'tinyint':
                case "bool":
                    $field = (new checkboxField($name))->addClass($entity->hrName($name))->setLabel($name)->setLength($length);
                    break;
                case "decimal":
                    $lengthParts = explode(",", $length);
                    $field = (new numberField($name))->setLabel($entity->hrName($name))->addClass($name)->setLength(array_sum($lengthParts))->setStep($lengthParts[1]);
                    break;
            }
        }
        if ($field && ($value = $entity->{$name} ?? false)) {
            if ($type === 'int' && !is_numeric($value)) {
                $value = 0;
            }
            $field->setValue($value);
        } elseif (in_array($type, ['varchar','text']) && $entity->{$name} === '0') { // This is needed as if("0") = false,  therefore text fields with 0 values were not being set correctly
            $field->setValue($value);
        }
        if ($disabled) {
            $field->isDisabled();
        }
        return $field;
    }
}
