<?php declare(strict_types=1);

namespace App\Twig\Extension;

use App\Tool\Utils;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\Fieldcollection;
use Pimcore\Model\Document\Page;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class OpenGraphExtension extends AbstractExtension
{
    private ?string $host;
    private ?string $currentUri;

    public function __construct(
        private RequestStack $requestStack
    ) {
        $request = $requestStack->getCurrentRequest();
        $this->host = $request?->getSchemeAndHttpHost();
        $this->currentUri = strtok($request?->getRequestUri() ?? '', '?') ?: null;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('get_page_og_meta_tags', [$this, 'getPageOGMeta']),
            new TwigFunction('get_data_object_og_meta_tags', [$this, 'getDataObjectOGMeta']),
        ];
    }

    public function getPageOGMeta(Page $page, string $language): array
    {
        $ogTags = [
            'twitter:card' => 'summary_large_image',
            'og:url' => $this->host . $this->currentUri,
        ];

        $title = $page->getTitle() ?: $page->getProperty('OGTitlePlaceholder') ?: $page->getProperty('navigation_title') ?: $page->getProperty('titlePostfix');
        if ($title) {
            $ogTags['og:title'] = $title;
            $ogTags['twitter:title'] = $title;
        }

        $description = $page->getDescription() ?: $page->getProperty('OGDescriptionPlaceholder') ?: $title;
        if ($description) {
            $description = Utils::cutStringRespectingWhitespace(strip_tags($description), 300);
            $ogTags['og:description'] = $description;
            $ogTags['twitter:description'] = $description;
        }

        $image = $page->getEditable('article-image')?->getImage() ?: $page->getProperty('OGImagePlaceholder');
        if ($image) {
            $ogTags['og:image'] = $this->host . Utils::thumbnail($image, 'OpenGraphImage');
            $ogTags['twitter:image'] = $this->host . Utils::thumbnail($image, 'TwitterImage');
            $ogTags['og:image:width'] = 1200;
            $ogTags['og:image:height'] = 630;
        }

        return $ogTags;
    }

    public function getDataObjectOGMeta(DataObject $object, string $language): array
    {
        $ogTags = [
            'twitter:card' => 'summary_large_image',
        ];

        $image = $this->getObjectImage($object);
        if ($image) {
            $ogTags['og:image'] = $this->host . Utils::thumbnail($image, 'OpenGraphImage');
            $ogTags['twitter:image'] = $this->host . Utils::thumbnail($image, 'TwitterImage');
            $ogTags['og:image:width'] = 1200;
            $ogTags['og:image:height'] = 630;
        }

        if (method_exists($object, 'getUrl')) {
            $ogTags['og:url'] = $this->host . $object->getUrl($language);
        }

        if (method_exists($object, 'getName')) {
            $ogTags['og:title'] = $object->getName($language);
            $ogTags['twitter:title'] = $object->getName($language);
        }

        $description = $this->getObjectDescription($object, $language);
        if ($description) {
            $description = Utils::cutStringRespectingWhitespace(strip_tags($description), 300);
            $ogTags['og:description'] = $description;
            $ogTags['twitter:description'] = $description;
        }

        return $ogTags;
    }

    private function getObjectImage(DataObject $object): ?DataObject\Image
    {
        if (method_exists($object, 'getPreviewImage')) {
            return $object->getPreviewImage();
        } elseif (method_exists($object, 'getTeaserImage')) {
            return $object->getTeaserImage();
        } elseif (method_exists($object, 'getContent') && ($content = $object->getContent()) instanceof Fieldcollection) {
            foreach ($content->getItems() as $block) {
                if ($block->getType() === 'ImageList') {
                    return $block->getImage();
                } elseif ($block->getType() === 'GallerySlider' && !empty($block->getImages())) {
                    return current($block->getImages());
                }
            }
        }
        return null;
    }

    private function getObjectDescription(DataObject $object, string $language): ?string
    {
        $descriptionElements = ['getPerex', 'getPreviewDescription', 'getDescription', 'getContent'];
        foreach ($descriptionElements as $element) {
            if (method_exists($object, $element) && ($content = $object->{$element}($language))) {
                if ($content instanceof Fieldcollection) {
                    foreach ($content->getItems() as $block) {
                        if ($block->getType() === 'TextBlock') {
                            return strip_tags($block->getText($language));
                        }
                    }
                } else {
                    return strip_tags($content);
                }
            }
        }
        return null;
    }
}
