<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Seo;

use CpCreation\VitiCore\Contact\ContactProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;

#[AsTwigComponent('seo:SiteStructuredData', template: '@components/seo/SiteStructuredData.html.twig')]
final class SiteStructuredData
{
    public ?string $pageTitle = null;
    public ?string $homepageTitle = null;
    public bool $includeBreadcrumb = true;

    public function __construct(
        private readonly ContactProvider $contactProvider,
        private readonly RequestStack $requestStack,
    ) {}

    /**
     * @return array<string, mixed>|null
     */
    public function getSchema(): ?array
    {
        $request = $this->requestStack->getCurrentRequest();
        $businessName = $this->contactProvider->getBusinessName();

        if (null === $request || null === $businessName) {
            return null;
        }

        $businessUrl = $request->getUriForPath('/');
        $pageUrl = $request->getUriForPath($request->getPathInfo());
        $wineryId = $businessUrl . '#winery';
        $websiteId = $businessUrl . '#website';
        $pageTitle = $this->normalizeText($this->pageTitle);
        $homepageTitle = $this->normalizeText($this->homepageTitle) ?? $businessName;
        $graph = [[
            '@type' => 'WebSite',
            '@id' => $websiteId,
            'url' => $businessUrl,
            'name' => $businessName,
            'publisher' => ['@id' => $wineryId],
            'inLanguage' => $request->getLocale(),
        ]];

        if (!$this->isHomepage($request) && null !== $pageTitle) {
            $webPage = [
                '@type' => 'WebPage',
                '@id' => $pageUrl . '#webpage',
                'url' => $pageUrl,
                'name' => $pageTitle,
                'isPartOf' => ['@id' => $websiteId],
                'about' => ['@id' => $wineryId],
                'inLanguage' => $request->getLocale(),
            ];

            if ($this->includeBreadcrumb) {
                $breadcrumbId = $pageUrl . '#breadcrumb';
                $webPage['breadcrumb'] = ['@id' => $breadcrumbId];
                $graph[] = $webPage;
                $graph[] = [
                    '@type' => 'BreadcrumbList',
                    '@id' => $breadcrumbId,
                    'itemListElement' => [
                        [
                            '@type' => 'ListItem',
                            'position' => 1,
                            'name' => $homepageTitle,
                            'item' => $businessUrl,
                        ],
                        [
                            '@type' => 'ListItem',
                            'position' => 2,
                            'name' => $pageTitle,
                            'item' => $pageUrl,
                        ],
                    ],
                ];
            } else {
                $graph[] = $webPage;
            }
        }

        return [
            '@context' => 'https://schema.org',
            '@graph' => $graph,
        ];
    }

    public function getSchemaJson(): ?string
    {
        $schema = $this->getSchema();
        if (null === $schema) {
            return null;
        }

        return json_encode(
            $schema,
            \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_APOS | \JSON_HEX_QUOT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR,
        );
    }

    private function isHomepage(Request $request): bool
    {
        $route = $request->attributes->get('_canonical_route', $request->attributes->get('_route'));
        if (\is_string($route) && ('homepage' === $route || str_starts_with($route, 'homepage.'))) {
            return true;
        }

        return '/' === $request->getPathInfo();
    }

    private function normalizeText(?string $value): ?string
    {
        if (null === $value) {
            return null;
        }

        $value = html_entity_decode(strip_tags($value), \ENT_QUOTES | \ENT_HTML5, 'UTF-8');
        $value = mb_trim($value);

        return '' !== $value ? $value : null;
    }
}
