<?php

declare(strict_types=1);

namespace a9f\Typo3Fractor\Helper;

trait FlexFormHelperTrait
{
    protected function extractDomElementByKey(?\DOMElement $element, string $key): ?\DOMElement
    {
        if (! $element instanceof \DOMElement) {
            return null;
        }

        foreach ($element->childNodes as $childNode) {
            if (! $childNode instanceof \DOMElement) {
                continue;
            }

            $itemKey = $childNode->nodeName;
            if ($key === $itemKey) {
                return $childNode;
            }
        }

        return null;
    }

    protected function extractDomElementFromArrayByIndex(?\DOMElement $element, string $index): ?\DOMElement
    {
        if (! $element instanceof \DOMElement) {
            return null;
        }

        foreach ($element->childNodes as $childNode) {
            if (! $childNode instanceof \DOMElement) {
                continue;
            }

            if (! $childNode->hasAttribute('index')) {
                continue;
            }

            $indexValue = $childNode->getAttribute('index');

            if ($childNode->nodeName === 'numIndex' && $index === $indexValue) {
                return $childNode;
            }
        }

        return null;
    }

    protected function hasKey(?\DOMElement $columnItemConfigurationArray, string $configKey): bool
    {
        if (! $columnItemConfigurationArray instanceof \DOMElement) {
            return false;
        }

        foreach ($columnItemConfigurationArray->childNodes as $item) {
            if (! $item instanceof \DOMElement) {
                continue;
            }

            if ($this->isValue($item->nodeName, $configKey)) {
                return true;
            }
        }

        return false;
    }

    private function isConfigType(?\DOMElement $columnItemConfigurationArray, string $type): bool
    {
        if (! $columnItemConfigurationArray instanceof \DOMElement) {
            return false;
        }

        return $this->hasKeyValuePair($columnItemConfigurationArray, 'type', $type);
    }

    private function configIsOfRenderType(?\DOMElement $columnItemConfigurationArray, string $expectedRenderType): bool
    {
        if (! $columnItemConfigurationArray instanceof \DOMElement) {
            return false;
        }

        return $this->hasKeyValuePair($columnItemConfigurationArray, 'renderType', $expectedRenderType);
    }

    private function hasRenderType(\DOMElement $columnItemConfigurationArray): bool
    {
        $renderTypeItem = $this->extractDomElementByKey($columnItemConfigurationArray, 'renderType');
        return $renderTypeItem !== null;
    }

    private function hasKeyValuePair(\DOMElement $configValueArray, string $configKey, string $expectedValue): bool
    {
        foreach ($configValueArray->childNodes as $configItemValue) {
            if (! $configItemValue instanceof \DOMElement) {
                continue;
            }
            if (! $this->isValue($configItemValue->nodeName, $configKey)) {
                continue;
            }
            if (! $this->isValue($configItemValue->textContent, $expectedValue)) {
                continue;
            }
            return true;
        }

        return false;
    }

    private function removeChildElementFromDomElementByKey(\DOMElement $configValueArray, string $configKey): bool
    {
        $arrayItemToRemove = $this->extractDomElementByKey($configValueArray, $configKey);
        if ($arrayItemToRemove instanceof \DOMElement && $arrayItemToRemove->parentNode instanceof \DOMElement) {
            $arrayItemToRemove->parentNode->removeChild($arrayItemToRemove);
            return true;
        }

        return false;
    }

    private function isValue(string $element, string $value): bool
    {
        return $element === $value;
    }

    /**
     * @see https://stackoverflow.com/a/21885789
     */
    private function changeTagName(\DOMDocument $domDocument, \DOMElement $node, string $elementName): void
    {
        $newNode = $domDocument->createElement($elementName);
        foreach ($node->childNodes as $child) {
            $newNode->appendChild($domDocument->importNode($child, false));
        }

        // We don't need to copy the attributes because TCA doesn't have attributes

        if (! $node->parentNode instanceof \DOMNode) {
            return;
        }

        $node->parentNode->replaceChild($newNode, $node);
    }

    private function changeTcaType(\DOMDocument $domDocument, \DOMElement $configElement, string $newType): void
    {
        $toChangeItem = $this->extractDomElementByKey($configElement, 'type');
        if ($toChangeItem instanceof \DOMElement) {
            $toChangeItem->nodeValue = '';
            $toChangeItem->appendChild($domDocument->createTextNode($newType));
        }
    }
}
