<?php
/**
 * Schema.org JSON-LD helper.
 *
 * Centralizes structured data generation across the site so that every page
 * emits a consistent Organization + WebSite anchor (referenced by @id) plus
 * page-specific types (WebPage, Article, Product, BreadcrumbList, FAQPage, ...).
 *
 * Conventions:
 *  - Organization @id = APP_URL . '/#organization'
 *  - WebSite      @id = APP_URL . '/#website'
 *  - Page-specific schemas reference these via { "@id": ... }
 */
class Schema
{
    public const ORG_ID = '/#organization';
    public const SITE_ID = '/#website';

    public static function organizationId(): string
    {
        return APP_URL . self::ORG_ID;
    }

    public static function webSiteId(): string
    {
        return APP_URL . self::SITE_ID;
    }

    /**
     * Canonical Organization node for the whole site.
     */
    public static function organization(): array
    {
        $name = Lang::get('app_name');
        return [
            '@type' => 'Organization',
            '@id' => self::organizationId(),
            'name' => $name,
            'alternateName' => 'Coins & Banknotes Catalogue',
            'url' => APP_URL,
            'logo' => [
                '@type' => 'ImageObject',
                'url' => APP_URL . '/favicon.ico',
            ],
        ];
    }

    /**
     * Canonical WebSite node, with a SearchAction targeting article search.
     */
    public static function webSite(): array
    {
        return [
            '@type' => 'WebSite',
            '@id' => self::webSiteId(),
            'name' => Lang::get('app_name'),
            'alternateName' => 'Coins & Banknotes Catalogue',
            'url' => APP_URL,
            'inLanguage' => Lang::getLocale(),
            'publisher' => ['@id' => self::organizationId()],
            'potentialAction' => [
                '@type' => 'SearchAction',
                'target' => [
                    '@type' => 'EntryPoint',
                    'urlTemplate' => APP_URL . '/articles?q={search_term_string}',
                ],
                'query-input' => 'required name=search_term_string',
            ],
        ];
    }

    /**
     * Build a BreadcrumbList from [['name'=>..., 'item'=>absolute_url], ...].
     */
    public static function breadcrumbs(array $items): array
    {
        $list = [];
        foreach (array_values($items) as $i => $b) {
            $list[] = [
                '@type' => 'ListItem',
                'position' => $i + 1,
                'name' => $b['name'],
                'item' => $b['item'],
            ];
        }
        return [
            '@type' => 'BreadcrumbList',
            'itemListElement' => $list,
        ];
    }

    /**
     * Generic WebPage node, isPartOf the global WebSite.
     */
    public static function webPage(string $url, string $name, string $description = '', ?array $breadcrumbs = null): array
    {
        $page = [
            '@type' => 'WebPage',
            '@id' => $url . '#webpage',
            'url' => $url,
            'name' => $name,
            'isPartOf' => ['@id' => self::webSiteId()],
            'inLanguage' => Lang::getLocale(),
        ];
        if ($description !== '') {
            $page['description'] = $description;
        }
        if ($breadcrumbs) {
            $page['breadcrumb'] = self::breadcrumbs($breadcrumbs);
        }
        return $page;
    }

    /**
     * ContactPage variant referencing the Organization as mainEntity.
     */
    public static function contactPage(string $url, string $name, string $description = '', ?string $contactEmail = null, ?array $breadcrumbs = null): array
    {
        $page = self::webPage($url, $name, $description, $breadcrumbs);
        $page['@type'] = 'ContactPage';
        $page['@id'] = $url . '#contactpage';

        $org = ['@id' => self::organizationId()];
        if ($contactEmail) {
            $org = [
                '@type' => 'Organization',
                '@id' => self::organizationId(),
                'contactPoint' => [
                    '@type' => 'ContactPoint',
                    'contactType' => 'customer support',
                    'email' => $contactEmail,
                    'availableLanguage' => ['en'],
                ],
            ];
        }
        $page['mainEntity'] = $org;
        return $page;
    }

    /**
     * FAQPage from [['question'=>..., 'answer'=>...], ...].
     */
    public static function faqPage(array $qa): array
    {
        return [
            '@type' => 'FAQPage',
            'mainEntity' => array_map(function ($e) {
                return [
                    '@type' => 'Question',
                    'name' => $e['question'],
                    'acceptedAnswer' => [
                        '@type' => 'Answer',
                        'text' => $e['answer'],
                    ],
                ];
            }, array_values($qa)),
        ];
    }

    /**
     * Render one or more schema arrays as <script type="application/ld+json"> tags.
     * Accepts a single schema array or an array of schemas.
     * Adds @context automatically when missing.
     */
    public static function render($schema): string
    {
        if (empty($schema)) {
            return '';
        }
        $list = isset($schema['@type']) ? [$schema] : $schema;
        $out = '';
        foreach ($list as $node) {
            if (!is_array($node) || empty($node)) {
                continue;
            }
            if (!isset($node['@context'])) {
                $node = ['@context' => 'https://schema.org'] + $node;
            }
            $out .= '<script type="application/ld+json">'
                . json_encode($node, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
                . '</script>' . "\n";
        }
        return $out;
    }
}
