<?php
declare(strict_types = 1);
namespace InternetGalerie\Igshop2\Form\Element;

use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
use TYPO3\CMS\Backend\Form\Element\CheckboxToggleElement;
use TYPO3\CMS\Backend\Form\Element\InputTextElement;
use TYPO3\CMS\Backend\Form\Element\TextElement;
use TYPO3\CMS\Backend\Form\FormDataProvider\TcaCheckboxItems;
use TYPO3\CMS\Core\Configuration\Richtext;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Html\RteHtmlParser;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
use TYPO3\CMS\RteCKEditor\Form\Element\RichTextElement;
use TYPO3\CMS\RteCKEditor\Form\Resolver\RichTextNodeResolver;

class PropertyFieldsElement extends AbstractFormElement
{
    public function render():array
    {
        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
        $qb = $connectionPool->getQueryBuilderForTable('tx_igshop2_domain_model_category');
        $row = $this->data['databaseRow'];

        $fieldInformationResult = $this->renderFieldInformation();
        $resultArray = $this->mergeChildReturnIntoExistingResult($this->initializeResultArray(), $fieldInformationResult, false);

        $categories = [];
        $properties = [];
        $propertyUids = [];

        // Only show properties when product was already saved
        $categories = $row['category'];
        if(!empty($categories)) {
            // Get categories of product
            /*$categories = $qb->select('*')
                            ->from('tx_igshop2_product_category_mm')
                            ->join(
                                'tx_igshop2_product_category_mm',
                                'tx_igshop2_domain_model_category',
                                'cat',
                                'cat.uid = tx_igshop2_product_category_mm.uid_foreign'
                            )
                            ->where('uid_local = ' . $row['uid'])
                            ->andWhere('deleted = 0 AND hidden = 0')
                            ->orderBy('tx_igshop2_product_category_mm.sorting')
                            ->executeQuery()
                            ->fetchAllAssociative();*/

            // Get all properties for the product categories
            foreach($categories as $category) {
                $qb = $connectionPool->getQueryBuilderForTable('tx_igshop2_domain_model_property');
                $propertiesForCategory = $qb->select('*')
                                            ->from('tx_igshop2_category_property_mm')
                                            ->join(
                                                'tx_igshop2_category_property_mm',
                                                'tx_igshop2_domain_model_property',
                                                'prop',
                                                'prop.uid = tx_igshop2_category_property_mm.uid_foreign'
                                            )
                                            ->where('uid_local = ' . $category)
                                            ->andWhere('deleted = 0 AND hidden = 0')
                                            ->orderBy('tx_igshop2_category_property_mm.sorting')
                                            ->executeQuery()
                                            ->fetchAllAssociative();

                foreach($propertiesForCategory as $property) {
                    if(!in_array($property['uid'], $propertyUids)) {
                        $properties[] = $property;
                        $propertyUids[] = $property['uid'];
                    }
                }
            }

            // If there are no categories on the product, show all properties
            if(empty($categories)) {
                $qb = $connectionPool->getQueryBuilderForTable('tx_igshop2_domain_model_property');
                $properties = $qb->select('*')
                                ->from('tx_igshop2_domain_model_property')
                                ->andWhere('deleted = 0 AND hidden = 0')
                                ->orderBy('sorting')
                                ->executeQuery()
                                ->fetchAllAssociative();
            }

            // Only do something if there are properties
            if(is_numeric($row['uid']) && $row['uid'] > 0 && !empty($properties)) {
                $parameterArray = $this->data['parameterArray'];
                $productItemName = htmlspecialchars($parameterArray['itemFormElName']);
                $html = [];
                $i = 0;
                $sorting = 1;


                $propertyValueUids = [];
                // Loop through properties and generate field html
                foreach($properties as $property) {
                    $qb = $connectionPool->getQueryBuilderForTable('tx_igshop2_domain_model_propertyvalue');

                    $existingPropertyvalue = '';
                    if(is_numeric($row['uid']) && $row['uid'] > 0) {
                        $existingPropertyvalue = $qb->select('*')
                                            ->from('tx_igshop2_domain_model_propertyvalue')
                                            ->where('product = ' . $row['uid'])
                                            ->andWhere('property = ' . $property['uid'])
                                            ->andWhere('deleted = 0 AND hidden = 0')
                                            ->executeQuery()
                                            ->fetchAssociative();
                    }

                    $propertyValueUid = $existingPropertyvalue ? $existingPropertyvalue['uid'] : 'NEW' . $i;
                    $propertyValueUids[] = $propertyValueUid;

                    $prefix = htmlspecialchars('data[tx_igshop2_domain_model_propertyvalue][' . $propertyValueUid . ']');
                    

                    $valueFieldName = $this->getValueFieldName($property);
                    $propertyPartial = $property['field_type'];
                    
                    $itemValue = '';
                    if($existingPropertyvalue && $valueFieldName) {
                        $itemValue = (string)$existingPropertyvalue[$valueFieldName] ?? '';
                    }

                    $label = $property['name'];

                    if($propertyPartial == 'List') {
                        $label .= ' (Liste: Jede Zeile ist ein Listenpunkt)';
                    }

                    if($property['unit']) {
                        $label .= ' (' . $property['unit'] . ')';
                    }

                    $html[] = '<fieldset class="form-section">';
                    $html[] =   '<div class="form-group t3js-formengine-validation-marker t3js-formengine-palette-field">';
                    $html[] =       '<fieldset>';
                    $html[] =            '<input type="hidden" value="' . $sorting++ . '" ';
                    $html[] =            'name="' . $prefix . '[sorting]" class="form-control"';
                    $html[] =            ' />';
                    $html[] =            '<input type="hidden" value="' . $row['sys_language_uid'] . '" ';
                    $html[] =            'name="' . $prefix . '[sys_language_uid]" class="form-control"';
                    $html[] =            ' />';
                    $html[] =            '<input type="hidden" value="' . $row['pid'] . '" ';
                    $html[] =            'name="' . $prefix . '[pid]" class="form-control"';
                    $html[] =            ' />';
                    $html[] =            '<input type="hidden" value="' . $row['uid'] . '" ';
                    $html[] =            'name="' . $prefix . '[product]" class="form-control"';
                    $html[] =            ' />';
                    $html[] =            '<input type="hidden" value="' . $property['uid'] . '" ';
                    $html[] =            'name="' . $prefix . '[property]" class="form-control"';
                    $html[] =            ' />';

                    switch($propertyPartial) {
                        case 'Checkbox':
                            $checkboxToggleResultArray = $this->getCheckbox($label, $prefix, $valueFieldName, $itemValue);
                            $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $checkboxToggleResultArray, false);
                            $html[] = $checkboxToggleResultArray['html'];
                            break;
                        case 'Rte':
                            $rteResultArray = $this->getRte($row, $label, $prefix, $valueFieldName, $itemValue);
                            $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $rteResultArray, false);
                            $html[] = $rteResultArray['html'];
                            break;
                        default:
                            $textResultArray = $this->getText($label, $prefix, $valueFieldName, $itemValue);
                            $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $textResultArray, false);
                            $html[] = $textResultArray['html'];
                            break;
                    }
                    
                    $html[] =       '</fieldset>';
                    $html[] =   '</div>';
                    $html[] = '</fieldset>';

                    $i++;
                }

                $html[] = '<input type="hidden" value="' . count($properties) . '" ';
                $html[] = 'name="' . $productItemName . '" class="form-control"';
                $html[] = ' />';
                $resultArray['html'] = implode(LF, $html);
            }

        }

        return $resultArray;
    }

    protected function getText($label, $prefix, $valueFieldName, $itemValue): array
    {
        $textData = $this->data;
        $textData['parameterArray']['itemFormElName'] = $prefix . '[' . $valueFieldName  . ']';
        $textData['parameterArray']['itemFormElID'] = rtrim(str_replace(['][', '[', ']'], '_', $textData['parameterArray']['itemFormElName']), '_');
        $textData['parameterArray']['itemFormElValue'] = $itemValue;
        $textData['parameterArray']['fieldConf']['config']['nullable'] = true;
        $textData['parameterArray']['fieldConf']['label'] = $label;
        unset($textData['parameterArray']['fieldChangeFunc']['TBE_EDITOR_fieldChanged']);
        $textResultArray = [];
        if ($valueFieldName == 'property_value_textarea') {
            $textElement = GeneralUtility::makeInstance(TextElement::class, $this->nodeFactory, $textData);
        } else {
            $textElement = GeneralUtility::makeInstance(InputTextElement::class, $this->nodeFactory, $textData);
        }
        $textResultArray = $textElement->render();
        return $textResultArray;
    }

    protected function getCheckbox($label, $prefix, $valueFieldName, $itemValue): array
    {
        $checkboxToggleData = $this->data;
        $checkboxToggleData['parameterArray']['itemFormElName'] = $prefix . '[' . $valueFieldName  . ']';
        $checkboxToggleData['parameterArray']['itemFormElID'] = rtrim(str_replace(['][', '[', ']'], '_', $checkboxToggleData['parameterArray']['itemFormElName']), '_');
        $checkboxToggleData['parameterArray']['itemFormElValue'] = $itemValue;
        $checkboxToggleData['parameterArray']['fieldConf']['label'] = $label;
        $checkboxToggleData['parameterArray']['fieldConf']['config']['nullable'] = true;
        $checkboxToggleData['parameterArray']['fieldConf']['config']['items'] = [
            [
                'label' => '',
                'invertStateDisplay' => false
            ]
        ];
        unset($checkboxToggleData['parameterArray']['fieldChangeFunc']['TBE_EDITOR_fieldChanged']);
        $checkboxToggleElement = GeneralUtility::makeInstance(CheckboxToggleElement::class, $this->nodeFactory, $checkboxToggleData);
        $checkboxToggleResultArray = $checkboxToggleElement->render();
        return $checkboxToggleResultArray;
    }

    protected function getRte($row, $label, $prefix, $valueFieldName, $itemValue): array
    {
        $rteData = $this->data;
        $rteData['parameterArray']['itemFormElName'] = $prefix . '[' . $valueFieldName  . ']';
        $rteData['parameterArray']['itemFormElID'] = rtrim(str_replace(['][', '[', ']'], '_', $rteData['parameterArray']['itemFormElName']), '_');
        $rteData['parameterArray']['itemFormElValue'] = $itemValue;
        $rteData['parameterArray']['fieldConf']['label'] = $label;
        $rteData['parameterArray']['fieldConf']['config']['enableRichtext'] = true;
        $rteData['parameterArray']['fieldConf']['config']['richtextConfigurationName'] = '';
        unset($rteData['parameterArray']['fieldChangeFunc']['TBE_EDITOR_fieldChanged']);

        $richtextConfigurationProvider = GeneralUtility::makeInstance(Richtext::class);
        $richtextConfiguration = $richtextConfigurationProvider->getConfiguration(
            'tx_igshop2_domain_model_propertyvalue',
            $valueFieldName,
            $row['pid'],
            '',
            $rteData['parameterArray']['fieldConf']['config']
        );
        // Transform if richtext is not disabled in configuration
        if (!($richtextConfiguration['disabled'] ?? false)) {
            // remember RTE preset name
            $rteData['processedTca']['columns'][$valueFieldName]['config']['richtextConfigurationName'] = $fieldConfig['config']['richtextConfiguration'] ?? '';
            // Add final resolved configuration to TCA array
            $rteData['processedTca']['columns'][$valueFieldName]['config']['richtextConfiguration'] = $richtextConfiguration;
            // If eval=null is set for field, value might be null ... don't transform anything in this case.
            $rteData['databaseRow'][$valueFieldName] = null;
            if ($rteData['databaseRow'][$valueFieldName] !== null) {
                // Process "from-db-to-rte" on current value
                $richTextParser = GeneralUtility::makeInstance(RteHtmlParser::class);
                $rteData['databaseRow'][$valueFieldName] = $richTextParser->transformTextForRichTextEditor($rteData['databaseRow'][$valueFieldName], $richtextConfiguration['proc.'] ?? []);
            }
        }
        $rteData['parameterArray']['fieldConf']['config']['richtextConfiguration'] = $richtextConfiguration;
        $rteElement = GeneralUtility::makeInstance(RichTextElement::class, $this->nodeFactory, $rteData);
        $rteResultArray = $rteElement->render();
        return $rteResultArray;
    }

    protected function getValueFieldName($property)
    {
        switch ($property['field_type']) {
            case 'Checkbox':
            case 'Float':
                return 'property_value_number';
            case 'Textarea':
            case 'Rte':
                return 'property_value_textarea';
            default:
                return 'property_value';
        }
    }
}