<?php

namespace IMATHUZH\Qfq\Core\Renderer\FormElement\Bootstrap3;

use IMATHUZH\Qfq\Core\Form\FormElement\AbstractFormElement;
use IMATHUZH\Qfq\Core\Helper\HelperFormElement;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Renderer\BaseRenderer;
use IMATHUZH\Qfq\Core\Renderer\FormElement\Base\RadioButtonRenderer;

class Bootstrap3RadioButtonRenderer extends RadioButtonRenderer {

    /**
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return string
     * @throws \CodeException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderInput(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML): string {
        if (isset($fe->attributes[FE_BUTTON_CLASS])) {
            if ($fe->attributes[FE_BUTTON_CLASS] == '') {
                $fe->attributes[FE_BUTTON_CLASS] = 'btn-default';
            }
            // BS Buttons
            $html = $this->renderRadioButton($fe, $renderMode);
        } else {
            // Plain
            $html = $this->renderRadioPlain($fe, $renderMode);
        }
        return $html . HelperFormElement::getHelpBlock() . $fe->attributes[FE_INPUT_EXTRA_BUTTON_INFO];
    }

    /**
     * Renders the classic round radiobuttons
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function renderRadioPlain(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {
        $html = '';
        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);
        $htmlInputId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_INPUT;
        $minWidth = $fe->attributes[F_FE_MIN_WIDTH] ?? 0;
        $attributeBaseLabel = $minWidth > 0 ? Support::doAttribute(ATTRIBUTE_STYLE, 'min-width: ' . $minWidth . 'px; font-weight: 400;') : '';

        $orientation = ($fe->attributes[FE_MAX_LENGTH] > 1) ? ALIGN_HORIZONTAL : ALIGN_VERTICAL;
        $radioClass = ($orientation === ALIGN_HORIZONTAL) ? 'radio-inline' : 'radio';
        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $radioClass .= ' qfq-disabled';
        }

        $br = '';
        $replaceBrFlag = false;

        $jj = 0;
        for ($ii = 0; $ii < count($fe->itemValues); $ii++) {
            $jj++;
            $optionHtmlAttributes = $fe->htmlAttributes;
            $optionHtmlAttributes[HTML_ATTR_ID] = HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii);
            $optionHtmlAttributes[HTML_ATTR_VALUE] = $fe->itemKeys[$ii];
            $optionHtmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE] . '-' . $ii;

            if ($fe->itemKeys[$ii] == $fe->value) {
                $optionHtmlAttributes[FE_CHECKBOX_CHECKED] = FE_CHECKBOX_CHECKED;
            } else if (isset($optionHtmlAttributes[FE_CHECKBOX_CHECKED])) {
                unset($optionHtmlAttributes[FE_CHECKBOX_CHECKED]);
            }

            // '&nbsp;' - This is necessary to correctly align an empty input.
            $tmpValue = ($fe->itemValues[$ii] === '') ? '&nbsp;' : $fe->itemValues[$ii];

            $inputClass = implode(' ', $fe->cssClasses);
            $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
            $htmlElement = '<input ' . Support::arrayToXMLAttributes($optionHtmlAttributes) . $classAttr . '>' . $tmpValue;
            // Add checkmark for JSON mode (dynamic updates) or inline filter/edit mode
            $isInlineMode = ($fe->attributes[FE_INLINE_FILTER] ?? false) || ($fe->attributes[FE_INLINE_EDIT] ?? false);
            if ($renderMode == RENDER_MODE_JSON || $isInlineMode) {
                $htmlElement .= '<span class="checkmark" aria="hidden"></span>';
            }
            if ($fe->attributes[FE_MAX_LENGTH] > 1) {
                if ($jj == $fe->attributes[FE_MAX_LENGTH]) {
                    $jj = 0;
                    $br = '<br>';
                    $replaceBrFlag = true;
                } else {
                    $br = '';
                }
            }

            $wrapAttribute = Support::doAttribute(HTML_ATTR_TITLE, $fe->attributes[FE_TOOLTIP]);
            $wrapAttribute .= Support::doAttribute(HTML_ATTR_CLASS, $radioClass);

            $radioLabelId = HelperFormElement::getCheckboxRadioOptionId($fe->attributes[FE_HTML_ID], $ii, HTML_ID_EXTENSION_LABEL);
            $htmlElement = Support::wrapTag("<label $wrapAttribute $attributeBaseLabel id='$radioLabelId'>", $htmlElement) . $br;

            $html .= $htmlElement;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_SUB_ELEMENTS][$ii] = $htmlElement;

        }
        if ($renderMode == RENDER_MODE_JSON) {
            $apiElementToReplace = ($replaceBrFlag) ? HTML_LABEL . ', ' . HTML_BR : HTML_LABEL;
            $json[API_ELEMENT_UPDATE][$htmlInputId][API_ELEMENT_TO_REPLACE] = $apiElementToReplace;
            return $json;
        }

        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'btn-group-plain-bottom-right');
        $html .= $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML];

        if ($fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] !== '') {
            $html = Support::wrapTag('<div class="btn-group-plain-wrapper">', $html);
        }

        // Wrap in container div for inline filter/edit mode
        $isInlineMode = ($fe->attributes[FE_INLINE_FILTER] ?? false) || ($fe->attributes[FE_INLINE_EDIT] ?? false);
        if ($isInlineMode) {
            $wrapperClass = 'qfq-inline-radio';
            if ($fe->attributes[FE_INLINE_FILTER] ?? false) {
                $wrapperClass .= ' qfq-inline-filter';
            }
            $html = Support::wrapTag('<div class="' . $wrapperClass . '">', $html);
        }

        return $html;
    }

    /**
     * Renders bootstrap3 buttons instead of the classic round radiobuttons
     *
     * @param AbstractFormElement $fe
     * @param string $renderMode
     * @return array|bool[]|string
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function renderRadioButton(AbstractFormElement $fe, string $renderMode = RENDER_MODE_HTML) {
        $html = '';
        $wrap = BaseRenderer::getInstance()->wrap[WRAP_SETUP_ELEMENT][WRAP_SETUP_CLASS];
        $json = HelperFormElement::getFormElementForJson($fe, $wrap);
        $btnGroupId = $fe->attributes[FE_HTML_ID] . HTML_ID_EXTENSION_BUTTON_GROUP;

        if ($fe->attributes[FE_MODE] == FE_MODE_READONLY) {
            $fe->attributes[FE_BUTTON_CLASS] .= ' qfq-disabled-btn';
        }

        for ($ii = 0; $ii < count($fe->itemValues); $ii++) {
            $classActive = '';

            $optionHtmlAttributes = $fe->htmlAttributes;
            $optionHtmlAttributes[HTML_ATTR_ID] = $fe->attributes[FE_HTML_ID] . '-' . $ii;
            $optionHtmlAttributes[HTML_ATTR_VALUE] = $fe->itemKeys[$ii];
            $optionHtmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $fe->attributes[FE_DATA_REFERENCE] . '-' . $ii;

            if ($fe->itemKeys[$ii] == $fe->value) {
                $optionHtmlAttributes[FE_CHECKBOX_CHECKED] = FE_CHECKBOX_CHECKED;
                $classActive = ' active';
            }

            if ($fe->itemValues[$ii] == '') { // In case the value is empty, the rendered button looks bad. Set '&nbsp;'.
                $fe->itemValues[$ii] = '&nbsp;';
            }

            $inputClass = implode(' ', $fe->cssClasses);
            $classAttr = !empty($inputClass) ? ' class="' . trim($inputClass) . '"' : '';
            $htmlElement = '<input ' . Support::arrayToXMLAttributes($optionHtmlAttributes) . $classAttr . '>' . $fe->itemValues[$ii];

            $labelAttribute = Support::doAttribute(HTML_ATTR_TITLE, $fe->attributes[FE_TOOLTIP]);
            $labelAttribute .= Support::doAttribute(HTML_ATTR_CLASS, 'btn ' . $fe->attributes[FE_BUTTON_CLASS] . $classActive);
            $labelAttribute .= Support::doAttribute(HTML_ATTR_ID, $fe->attributes[FE_HTML_ID] . '-' . $ii . '-l');

            $htmlElement = Support::wrapTag("<label $labelAttribute>", $htmlElement);

            $html .= $htmlElement;
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_SUB_ELEMENTS][] = $htmlElement;
        }

        if ($renderMode == RENDER_MODE_JSON) {
            // Tells the JS what children have to be replaced.
            $json[API_ELEMENT_UPDATE][$btnGroupId][API_ELEMENT_TO_REPLACE] = HTML_LABEL;
            return $json;
        }

        $fe->attributes = HelperFormElement::prepareExtraButton($fe->attributes, true, 'extra-button-btn-group');
        $html .= $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML];

        // Build btn-group class - add qfq-inline-filter for inline filter mode
        $btnGroupClass = $fe->attributes[FE_TMP_EXTRA_BUTTON_HTML] === '' ? 'btn-group' : 'btn-group input-group';
        $isInlineFilter = $fe->attributes[FE_INLINE_FILTER] ?? false;
        if ($isInlineFilter) {
            $btnGroupClass .= ' qfq-inline-filter';
        }

        $html = Support::wrapTag('<div class="' . $btnGroupClass . '" data-toggle="buttons" id="' . $btnGroupId . '">', $html);

        return $html;
    }

    /**
     * @param AbstractFormElement $fe
     * @return array
     * @throws \CodeException
     * @throws \DbException
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function renderJson(AbstractFormElement $fe): array {

        if (isset($fe->attributes[FE_BUTTON_CLASS])) {
            if ($fe->attributes[FE_BUTTON_CLASS] == '') {
                $fe->attributes[FE_BUTTON_CLASS] = 'btn-default';
            }
            return $this->renderRadioButton($fe, RENDER_MODE_JSON);
        } else {
            return $this->renderRadioPlain($fe, RENDER_MODE_JSON);
        }
    }
}