<?php

declare(strict_types=1);

class SEO
{
    public static function title(string ...$parts): string
    {
        $siteName = Branding::siteName();
        $parts = array_filter($parts, fn(string $p) => $p !== '');
        if (empty($parts)) {
            return htmlspecialchars($siteName);
        }
        $parts[] = $siteName;
        $sep = HookSystem::applyFilter('seo.title_separator', ' - ');
        return htmlspecialchars(implode($sep, $parts));
    }

    public static function meta(string $description, string $keywords = ''): array
    {
        $meta = ['description' => htmlspecialchars(mb_substr($description, 0, 160))];
        $kw = $keywords ?: (string) Setting::get('meta_keywords', '');
        if ($kw !== '') {
            $meta['keywords'] = htmlspecialchars($kw);
        }
        return $meta;
    }

    

    public static function canonical(string $path): string
    {
        $base = self::siteUrl();
         
        $path = strtok($path, '?#') ?: $path;
         
         
        return rtrim($base, '/') . '/' . ltrim($path, '/');
    }

    

    public static function siteUrl(): string
    {
        $url = Setting::get('site_url', '');
        if ($url) {
            return rtrim((string) $url, '/');
        }

         
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        if (!preg_match('/^[a-zA-Z0-9._-]+(:\d+)?$/', $host)) {
            $host = 'localhost';
        }
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        return rtrim($scheme . '://' . $host, '/');
    }

    

    public static function ogTags(array $data): string
    {
        $html = '';
        $defaults = [
            'og:type' => 'website',
            'og:site_name' => Branding::siteName(),
            'og:locale' => str_replace('-', '_', Translator::locale()),
        ];

        $tags = array_merge($defaults, $data);
        foreach ($tags as $property => $content) {
            if ($content === null || $content === '') continue;
            $html .= '<meta property="' . htmlspecialchars($property) . '" content="' . htmlspecialchars((string) $content) . '">' . "\n";
        }

         
        $currentLocale = str_replace('-', '_', Translator::locale());
        foreach (Translator::available() as $lang) {
            $altLocale = str_replace('-', '_', $lang['code']);
            if ($altLocale !== $currentLocale) {
                $html .= '<meta property="og:locale:alternate" content="' . htmlspecialchars($altLocale) . '">' . "\n";
            }
        }

        return $html;
    }

    

    public static function twitterCard(array $data): string
    {
        $html = '';
        $defaults = ['twitter:card' => 'summary_large_image'];
        $tags = array_merge($defaults, $data);
        foreach ($tags as $name => $content) {
            if ($content === null || $content === '') continue;
            $html .= '<meta name="' . htmlspecialchars($name) . '" content="' . htmlspecialchars((string) $content) . '">' . "\n";
        }
        return $html;
    }

    

    public static function videoJsonLd(array $video, string $canonicalUrl): string
    {
        $siteUrl = self::siteUrl();
        $sid = isset($video['storage_id']) ? (int) $video['storage_id'] : null;
        $thumbUrl = '';
        if (!empty($video['video_folder'])) {
            $tp = VideoAsset::thumbUrlFromFolder($video['video_folder'], false, $sid);
            if ($tp !== '') {
                $thumbUrl = (str_starts_with($tp, 'http://') || str_starts_with($tp, 'https://')) ? $tp : $siteUrl . $tp;
            }
        } elseif (!empty($video['thumbnail'])) {
            $thumbUrl = (str_starts_with($video['thumbnail'], 'http://') || str_starts_with($video['thumbnail'], 'https://'))
                ? $video['thumbnail'] : $siteUrl . '/uploads/' . $video['thumbnail'];
        }

        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'VideoObject',
            'name' => $video['title'] ?? '',
            'description' => mb_substr(strip_tags($video['description'] ?? ''), 0, 300),
            'url' => html_entity_decode($canonicalUrl),
            'thumbnailUrl' => $thumbUrl,
            'uploadDate' => self::toIso8601($video['created_at'] ?? null),
        ];

         
        if (!empty($video['slug'])) {
            $schema['embedUrl'] = $siteUrl . '/embed/' . $video['slug'];
        }

         
        if (!empty($video['video_folder'])) {
            $videoFileUrl = VideoAsset::videoUrl($video['video_folder'], $sid);
            if ($videoFileUrl !== '') {
                $schema['contentUrl'] = (str_starts_with($videoFileUrl, 'http://') || str_starts_with($videoFileUrl, 'https://'))
                    ? $videoFileUrl : $siteUrl . $videoFileUrl;
            }
        }

        if (!empty($video['duration']) && (int) $video['duration'] > 0) {
            $d = (int) $video['duration'];
            $h = intdiv($d, 3600);
            $m = intdiv($d % 3600, 60);
            $s = $d % 60;
            $schema['duration'] = sprintf('PT%dH%dM%dS', $h, $m, $s);
        }

        if (!empty($video['views'])) {
            $schema['interactionStatistic'] = [
                '@type' => 'InteractionCounter',
                'interactionType' => 'https://schema.org/WatchAction',
                'userInteractionCount' => (int) $video['views'],
            ];
        }

        return '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . '</script>' . "\n";
    }

    

    public static function websiteJsonLd(): string
    {
        $siteUrl = self::siteUrl();
        $siteName = Branding::siteName();

        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'WebSite',
            'name' => $siteName,
            'url' => $siteUrl . '/',
            'potentialAction' => [
                '@type' => 'SearchAction',
                'target' => [
                    '@type' => 'EntryPoint',
                    'urlTemplate' => $siteUrl . '/search?q={search_term_string}',
                ],
                'query-input' => 'required name=search_term_string',
            ],
        ];

        return '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . '</script>' . "\n";
    }

    

    private static function toIso8601(?string $datetime): string
    {
        if ($datetime === null || $datetime === '') {
            return date('c');
        }
        $ts = strtotime($datetime);
        return $ts !== false ? date('c', $ts) : date('c');
    }

    

    public static function breadcrumbJsonLd(array $crumbs): string
    {
        $items = [];
        foreach ($crumbs as $i => $crumb) {
            $items[] = [
                '@type' => 'ListItem',
                'position' => $i + 1,
                'name' => $crumb['name'],
                'item' => $crumb['url'] ?? '',
            ];
        }
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'BreadcrumbList',
            'itemListElement' => $items,
        ];
        return '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . '</script>' . "\n";
    }

    

    public static function imageGalleryJsonLd(array $album, array $images, string $url): string
    {
        $media = [];
        foreach (array_slice($images, 0, 60) as $im) {
            $u = $im['url'] ?? '';
            if ($u === '') continue;
            $obj = ['@type' => 'ImageObject', 'contentUrl' => $u];
            if (!empty($im['w'])) $obj['width'] = (int) $im['w'];
            if (!empty($im['h'])) $obj['height'] = (int) $im['h'];
            $media[] = $obj;
        }
        if (empty($media)) return '';
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'ImageGallery',
            'name' => $album['title'] ?? '',
            'url' => $url,
            'numberOfItems' => (int) ($album['image_count'] ?? count($media)),
            'associatedMedia' => $media,
        ];
        if (!empty($album['description'])) {
            $schema['description'] = mb_substr(trim(strip_tags($album['description'])), 0, 300);
        }
        return '<script type="application/ld+json">' . json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . '</script>' . "\n";
    }

    

    public static function renderHead(array $data): string
    {
        $html = '';

         
        if (!empty($data['canonicalUrl'])) {
            $html .= '<link rel="canonical" href="' . htmlspecialchars($data['canonicalUrl']) . '">' . "\n";
        }

         
        if (!empty($data['alternates'])) {
            foreach ($data['alternates'] as $hl => $hu) {
                $html .= '<link rel="alternate" hreflang="' . htmlspecialchars($hl) . '" href="' . htmlspecialchars($hu) . '">' . "\n";
            }
        }

         
        if (!empty($data['ogTags'])) {
            $html .= self::ogTags($data['ogTags']);
        }

         
        if (!empty($data['twitterCard'])) {
            $html .= self::twitterCard($data['twitterCard']);
        }

         
        if (!empty($data['jsonLd'])) {
            $html .= $data['jsonLd'];
        }

        return $html;
    }
}
