<?php

namespace IMATHUZH\Qfq\Core\Form\FormElement;

use IMATHUZH\Qfq\Core\Form\FeFactory;
use IMATHUZH\Qfq\Core\Form\Form;
use IMATHUZH\Qfq\Core\Helper\Logger;
use IMATHUZH\Qfq\Core\Helper\Support;

class TemplateGroupFormElement extends ContainerFormElement {
    public string $addButtonId;
    public string $qfqFieldsName;
    public string $templateName;
    public string $targetName;
    public int $initialChildCount = 0;
    /**
     * @var array Contains 0-n additional arrays which contain Form Elements
     */
    public array $initialElementGroups = array();

    /**
     * @param $attributes
     * @param Form|null $form
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function __construct($attributes, ?Form $form = null) {
        parent::__construct($attributes, $form);

        $this->handleDefaultValues();
        $this->handleElementIdsAndNames();

        // Nothing else to do if TG has no children
        if (count($this->formElements) == 0) return;

        $this->handleMaxCopies();
        $this->handleHtmlAttributes();

        $this->handleChildCount();
        $this->handleInitialElementGroups();
    }

    /**
     * Prepare ids and names for special html elements of the template group
     *
     * @return void
     */
    private function handleElementIdsAndNames(): void {
        $this->addButtonId = 'add_button_' . $this->attributes[FE_ID];
        $this->qfqFieldsName = 'qfq_fields_' . $this->attributes[FE_ID]; // ='qfq-fields'
        $this->templateName = 'template_' . $this->attributes[FE_ID]; // ='template'
        $this->targetName = 'target_' . $this->attributes[FE_ID]; // ='template'
    }


    /**
     * Set default values for template group specific attributes (unless they are specified by the user)
     *
     * @return void
     */
    private function handleDefaultValues(): void {
        Support::setIfNotSet($this->attributes, FE_TEMPLATE_GROUP_ADD_CLASS, 'btn btn-default');
        Support::setIfNotSet($this->attributes, FE_TEMPLATE_GROUP_ADD_TEXT, 'Add');
        Support::setIfNotSet($this->attributes, FE_TEMPLATE_GROUP_REMOVE_CLASS, 'btn btn-default');
        Support::setIfNotSet($this->attributes, FE_TEMPLATE_GROUP_REMOVE_TEXT, 'Remove');
        Support::setIfNotSet($this->attributes, FE_TEMPLATE_GROUP_CLASS);
        Support::setIfNotSet($this->attributes, FE_MAX_LENGTH, '5', '');
    }

    /**
     * Child FE's of type checkbox need the NAME_TG_COPIES attribute for some reason
     *
     * @return void
     */
    private function handleMaxCopies(): void {
        foreach ($this->formElements as $fe) {
            if ($fe->attributes[FE_TYPE] == FE_TYPE_CHECKBOX) {
                $fe->attributes[NAME_TG_COPIES] = $this->attributes[FE_MAX_LENGTH];
            }
        }
    }

    /**
     * Prepares $this->htmlAttributes with all attributes for the TG's main wrapping div
     *
     * @return void
     */
    private function handleHtmlAttributes(): void {
        $this->htmlAttributes['class'] = $this->qfqFieldsName;
        $this->htmlAttributes[HTML_ATTR_ID] = $this->targetName;
        $this->htmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $this->attributes[FE_DATA_REFERENCE];
        $this->htmlAttributes['data-qfq-line-template'] = '#' . $this->templateName;
        $this->htmlAttributes['data-qfq-line-add-button'] = '#' . $this->addButtonId;
    }


    /**
     * Count the amount of children that are already displayed on load and save that number in $this->initialChildCount
     *
     * @return void
     */
    private function handleChildCount(): void {
        // TODO: isn't this logically incorrect?
        foreach ($this->formElements as $childFE) {
            if (empty(($childFE->valueArray))) {
                $this->initialChildCount = 1;
            } else {
                $this->initialChildCount = min(count($childFE->valueArray), $this->attributes[FE_MAX_LENGTH]);
            }
        }
    }


    /**
     * Instantiates and prepares $this->initialElementGroups
     * Which is an array of all groups of elements that should already be displayed on load.
     * each group is another array in the array, containing all form elements of that group.
     *
     * @return void
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    private function handleInitialElementGroups(): void {
        $record = $this->store->getStore(STORE_RECORD); // current values
        if ($record === false || count($record) === 0) {
            return;
        }
        $default = $this->store->getStore(STORE_TABLE_DEFAULT); // current defaults

        for ($ii = 1; $ii <= $this->initialChildCount; $ii++) {

            $elementGroup = array();

            // Per copy, iterate over all templateGroup FormElements.
            foreach ($this->formElements as $fe) {
                $initialAttributes = $fe->initialAttributes;

                $initialAttributes[FE_NAME] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe->attributes[FE_NAME]);
                $initialAttributes[FE_LABEL] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe->attributes[FE_LABEL]);
                $initialAttributes[FE_NOTE] = str_replace(FE_TEMPLATE_GROUP_NAME_PATTERN, $ii, $fe->attributes[FE_NOTE]);
                $initialAttributes[FE_TG_INDEX] = $ii;

                if (!empty($fe->valueArray) && isset($fe->valueArray[$ii - 1])) {
                    $arrayKey = array_keys($fe->valueArray[$ii - 1])[0];
                    $initialAttributes[FE_VALUE] = $fe->valueArray[$ii - 1][$arrayKey];
                }

                $newFE = FeFactory::createFormElement($initialAttributes, $fe->form);

                array_push($elementGroup, $newFE);
            }

            array_push($this->initialElementGroups, $elementGroup);
        }
    }
}