<?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\Tests\Twig;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Seo\SiteStructuredData;
use CpCreation\VitiCore\Contact\ContactProvider;
use CpCreation\VitiCore\Contact\Model\Contact;
use CpCreation\VitiCore\Contact\Repository\ContactRepository;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;

final class SiteStructuredDataTest extends TestCase
{
    public function testBuildsWebsiteWebPageAndBreadcrumbSchemas(): void
    {
        $component = $this->createComponent('https://example.com/notre-histoire', 'home');
        $component->pageTitle = 'Notre histoire | Maison Exemple';
        $component->homepageTitle = 'Maison Exemple | Champagne';

        $schema = $component->getSchema();

        self::assertSame('https://schema.org', $schema['@context'] ?? null);
        self::assertSame('WebSite', $schema['@graph'][0]['@type'] ?? null);
        self::assertSame('https://example.com/#winery', $schema['@graph'][0]['publisher']['@id'] ?? null);
        self::assertSame('WebPage', $schema['@graph'][1]['@type'] ?? null);
        self::assertSame('https://example.com/notre-histoire', $schema['@graph'][1]['url'] ?? null);
        self::assertSame('https://example.com/notre-histoire#breadcrumb', $schema['@graph'][1]['breadcrumb']['@id'] ?? null);
        self::assertSame('BreadcrumbList', $schema['@graph'][2]['@type'] ?? null);
        self::assertSame('Maison Exemple | Champagne', $schema['@graph'][2]['itemListElement'][0]['name'] ?? null);
        self::assertSame('Notre histoire | Maison Exemple', $schema['@graph'][2]['itemListElement'][1]['name'] ?? null);
    }

    public function testHomepageOnlyBuildsTheWebsiteSchema(): void
    {
        $component = $this->createComponent('https://example.com/', 'homepage');
        $component->pageTitle = 'Maison Exemple';

        $schema = $component->getSchema();

        self::assertCount(1, $schema['@graph'] ?? []);
        self::assertSame('WebSite', $schema['@graph'][0]['@type'] ?? null);
        self::assertSame('Maison Exemple', $schema['@graph'][0]['name'] ?? null);
    }

    public function testCanOmitTheBreadcrumbOnAProductPage(): void
    {
        $component = $this->createComponent('https://example.com/boutique/brut/cuvee', 'shop_product');
        $component->pageTitle = 'Cuvée Brut';
        $component->includeBreadcrumb = false;

        $schema = $component->getSchema();

        self::assertCount(2, $schema['@graph'] ?? []);
        self::assertSame('WebPage', $schema['@graph'][1]['@type'] ?? null);
        self::assertArrayNotHasKey('breadcrumb', $schema['@graph'][1]);
    }

    public function testEscapesMarkupInTheJsonScript(): void
    {
        $component = $this->createComponent('https://example.com/contact', 'contact');
        $component->pageTitle = '<strong>Contact</strong></script>';

        $json = $component->getSchemaJson();

        self::assertNotNull($json);
        self::assertStringContainsString('"name":"Contact"', $json);
        self::assertStringNotContainsString('<strong>', $json);
        self::assertStringNotContainsString('</script>', $json);
    }

    public function testDoesNotBuildSchemaWithoutContact(): void
    {
        $repository = $this->createMock(ContactRepository::class);
        $repository->expects(self::once())->method('findOne')->willReturn(null);
        $requestStack = new RequestStack();
        $requestStack->push(Request::create('https://example.com/'));

        $component = new SiteStructuredData(new ContactProvider($repository), $requestStack);

        self::assertNull($component->getSchema());
        self::assertNull($component->getSchemaJson());
    }

    private function createComponent(string $url, string $canonicalRoute): SiteStructuredData
    {
        $contact = new Contact();
        $contact->setCompany('Maison Exemple');

        $repository = $this->createMock(ContactRepository::class);
        $repository->method('findOne')->willReturn($contact);
        $request = Request::create($url);
        $request->attributes->set('_canonical_route', $canonicalRoute);
        $request->setLocale('fr');
        $requestStack = new RequestStack();
        $requestStack->push($request);

        return new SiteStructuredData(new ContactProvider($repository), $requestStack);
    }
}
