<?php

namespace Core\System;

class SeoManager
{
    protected static array $data = [];
    protected static bool $initialized = false;

    public static function init(array $context = []): void
    {
        if (self::$initialized) {
            return;
        }

        self::$initialized = true;
        $siteName = ThemeManager::getSetting('site_name', 'Website');
        $siteDescription = self::prepareMetaDescription((string) ThemeManager::getSetting('site_description', ''));
        $siteKeywords = trim((string) ThemeManager::getSetting('site_keywords', ''));

        self::$data = [
            'type'        => 'default',
            'title'       => $siteName,
            'description' => $siteDescription,
            'keywords'    => $siteKeywords,
            'image'       => self::fixImagePath((string) ThemeManager::getSetting('seo_default_image', '')),
            'canonical'   => self::currentUrl(),
            'robots'      => 'index, follow',
            'lang'        => $context['lang'] ?? 'en',
            'dir'         => $context['dir'] ?? 'ltr',
            'schema'      => [],
            'meta_title'  => $siteName,
            'og_title'    => $siteName,
            'og_description' => $siteDescription,
            'image_width' => 1200,
            'image_height' => 630,
            'image_type'  => null,
        ];
    }

    protected static function ensureInit(): void
    {
        if (!self::$initialized) {
            self::init();
        }
    }

    protected static function ensureDefaultImage(): void
    {
        if (!empty(self::$data['image'])) {
            return;
        }

        $default = (string) ThemeManager::getSetting('seo_default_image', '');
        if ($default !== '') {
            self::$data['image'] = self::fixImagePath($default);
        }
    }


    protected static function prepareMetaTitle(string $text, string $fallback = ''): string
    {
        $text = trim(strip_tags($text));
        return $text !== '' ? $text : $fallback;
    }

    protected static function resolveImageDimensions(string $imageUrl): array
    {
        $fallback = ['width' => 1200, 'height' => 630];

        if ($imageUrl === '') {
            return $fallback;
        }

        $path = parse_url($imageUrl, PHP_URL_PATH);
        if (!is_string($path) || $path === '') {
            return $fallback;
        }

        $absolute = ROOT_PATH . '/' . ltrim($path, '/');
        if (!is_file($absolute)) {
            return $fallback;
        }

        $size = @getimagesize($absolute);
        if (!$size || empty($size[0]) || empty($size[1])) {
            return $fallback;
        }

        return ['width' => (int)$size[0], 'height' => (int)$size[1]];
    }

    protected static function detectMimeType(string $imageUrl): ?string
    {
        $path = strtolower((string)parse_url($imageUrl, PHP_URL_PATH));
        if ($path === '') {
            return null;
        }

        return match (pathinfo($path, PATHINFO_EXTENSION)) {
            'jpg', 'jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'webp' => 'image/webp',
            'gif' => 'image/gif',
            default => null,
        };
    }

    public static function fromHome(): void
    {
        self::ensureInit();
        self::merge([
            'type'        => 'home',
            'title'       => ThemeManager::getSetting('site_name', 'Website'),
            'description' => self::prepareMetaDescription((string) ThemeManager::getSetting('site_description', '')),
            'og_title'    => ThemeManager::getSetting('site_name', 'Website'),
            'og_description' => self::prepareMetaDescription((string) ThemeManager::getSetting('site_description', '')),
            'canonical'   => self::absoluteUrl(url('/')),
        ]);
        self::ensureDefaultImage();
    }

    public static function fromProduct(array $product): void
    {
        self::ensureInit();

        $siteName = ThemeManager::getSetting('site_name', 'Website');
        $name = trim((string)($product['title'] ?? $product['name'] ?? 'Product'));
        $metaTitle = self::prepareMetaTitle((string)($product['meta_title'] ?? ''), $name);
        $pageTitle = $metaTitle !== '' ? ($metaTitle . ' | ' . $siteName) : $siteName;
        $metaDescription = self::prepareMetaDescription((string)(
            $product['meta_description']
            ?? $product['short_description']
            ?? $product['description']
            ?? ''
        ));
        $ogTitle = self::prepareMetaTitle((string)($product['og_title'] ?? ''), $metaTitle !== '' ? $metaTitle : $name);
        $ogDescription = self::prepareMetaDescription((string)(
            $product['og_description']
            ?? $product['meta_description']
            ?? $product['short_description']
            ?? $product['description']
            ?? ''
        ));
        $image = self::fixImagePath((string)($product['og_image'] ?? $product['featured_image'] ?? $product['image'] ?? ''));
        $canonical = self::absoluteUrl(url('/product/' . (!empty($product['slug']) ? $product['slug'] : (int)($product['id'] ?? 0))));
        $price = null;
        if (!empty($product['sale_price']) && (float)$product['sale_price'] > 0) {
            $price = (float)$product['sale_price'];
        } elseif (isset($product['price']) && $product['price'] !== '') {
            $price = (float)$product['price'];
        }

        $brandName = trim((string)($product['schema_brand'] ?? ''));
        if ($brandName === '') {
            $brandName = $siteName;
        }

        $imageMeta = self::resolveImageDimensions($image);
        $imageType = self::detectMimeType($image);

        self::merge([
            'type'        => 'product',
            'title'       => $pageTitle,
            'meta_title'  => $metaTitle !== '' ? $metaTitle : $name,
            'description' => $metaDescription,
            'og_title'    => $ogTitle,
            'og_description' => $ogDescription,
            'image'       => $image,
            'image_width' => $imageMeta['width'],
            'image_height' => $imageMeta['height'],
            'image_type'  => $imageType,
            'canonical'   => $canonical,
            'schema'      => array_filter([
                '@context' => 'https://schema.org',
                '@type' => 'Product',
                'name' => $name,
                'description' => $metaDescription !== '' ? $metaDescription : $ogDescription,
                'image' => $image !== '' ? [$image] : null,
                'sku' => $product['sku'] ?? null,
                'gtin' => $product['schema_gtin'] ?? $product['barcode'] ?? null,
                'mpn' => $product['schema_mpn'] ?? null,
                'brand' => [
                    '@type' => 'Brand',
                    'name' => $brandName,
                ],
                'offers' => array_filter([
                    '@type' => 'Offer',
                    'priceCurrency' => ThemeManager::getSetting('currency', 'DZD'),
                    'price' => $price,
                    'availability' => ((int)($product['stock_quantity'] ?? 0) > 0)
                        ? 'https://schema.org/InStock'
                        : 'https://schema.org/OutOfStock',
                    'itemCondition' => 'https://schema.org/NewCondition',
                    'url' => $canonical,
                    'seller' => [
                        '@type' => 'Organization',
                        'name' => $siteName,
                    ],
                ], static fn ($value) => $value !== null && $value !== ''),
            ], static fn ($value) => $value !== null && $value !== ''),
        ]);

        self::ensureDefaultImage();
    }

    public static function fromPage(array $page): void
    {
        self::ensureInit();

        $title = trim((string)($page['meta_title'] ?? $page['title'] ?? ''));
        $description = self::prepareMetaDescription((string)($page['meta_description'] ?? $page['content'] ?? ''));
        $canonical = self::absoluteUrl(url('/' . ltrim((string)($page['slug'] ?? ''), '/')));

        self::merge([
            'type'        => 'page',
            'title'       => $title,
            'meta_title'  => $title,
            'description' => $description,
            'image'       => self::fixImagePath((string)($page['image'] ?? '')),
            'og_title'    => $title,
            'og_description' => $description,
            'canonical'   => $canonical,
            'schema'      => [
                '@context' => 'https://schema.org',
                '@type'    => 'WebPage',
                'name'     => $title,
                'description' => $description,
                'url'      => $canonical,
            ],
        ]);

        self::ensureDefaultImage();
    }

    /**
     * Build WebSite + Organization schema for the home page.
     * Call this from HomeController::index() after SeoManager::init().
     */
    public static function addWebsiteSchema(): void
    {
        self::ensureInit();

        $siteName    = ThemeManager::getSetting('site_name', 'Website');
        $siteDesc    = self::prepareMetaDescription((string) ThemeManager::getSetting('site_description', ''));
        $homeUrl     = self::absoluteUrl('/');
        $logoRaw     = (string) ThemeManager::getSetting('site_logo', '');
        $logoUrl     = $logoRaw !== '' ? self::absoluteUrl(self::fixImagePath($logoRaw)) : '';
        $defaultImg  = (string) ThemeManager::getSetting('seo_default_image', '');
        $imageUrl    = $defaultImg !== '' ? self::absoluteUrl(self::fixImagePath($defaultImg)) : $logoUrl;

        // Compose as @graph with two nodes for richer coverage
        $graph = [
            [
                '@type'           => 'WebSite',
                '@id'             => $homeUrl . '#website',
                'url'             => $homeUrl,
                'name'            => $siteName,
                'description'     => $siteDesc,
                'potentialAction' => [
                    '@type'       => 'SearchAction',
                    'target'      => [
                        '@type'       => 'EntryPoint',
                        'urlTemplate' => $homeUrl . 'products?q={search_term_string}',
                    ],
                    'query-input' => 'required name=search_term_string',
                ],
            ],
            [
                '@type'  => 'Organization',
                '@id'    => $homeUrl . '#organization',
                'name'   => $siteName,
                'url'    => $homeUrl,
            ],
        ];

        if ($logoUrl !== '') {
            $graph[1]['logo'] = ['@type' => 'ImageObject', 'url' => $logoUrl];
        }
        if ($imageUrl !== '') {
            $graph[0]['image'] = $imageUrl;
        }

        self::merge([
            'schema' => [
                '@context' => 'https://schema.org',
                '@graph'   => $graph,
            ],
        ]);
    }

    public static function set(array $override): void
    {
        self::ensureInit();
        if (isset($override['image'])) {
            $override['image'] = self::fixImagePath((string)$override['image']);
            $imageMeta = self::resolveImageDimensions((string)$override['image']);
            $override['image_width'] = $override['image_width'] ?? $imageMeta['width'];
            $override['image_height'] = $override['image_height'] ?? $imageMeta['height'];
            $override['image_type'] = $override['image_type'] ?? self::detectMimeType((string)$override['image']);
        }
        if (isset($override['canonical'])) {
            $override['canonical'] = self::absoluteUrl((string)$override['canonical']);
        }
        if (isset($override['description'])) {
            $override['description'] = self::prepareMetaDescription((string)$override['description']);
        }
        self::merge($override);
        self::ensureDefaultImage();
    }

    public static function get(): array
    {
        self::ensureInit();
        self::ensureDefaultImage();
        return self::$data;
    }

    protected static function prepareMetaDescription(string $text): string
    {
        $text = trim(strip_tags($text));
        $text = preg_replace('/\s+/u', ' ', $text);
        if (mb_strlen($text) > 160) {
            $text = mb_substr($text, 0, 157) . '…';
        }
        return $text;
    }

    protected static function fixImagePath(string $path): string
    {
        $path = trim($path);
        if ($path === '') {
            return '';
        }
        if ($path[0] !== '/' && !preg_match('#^https?://#i', $path)) {
            $path = '/' . ltrim($path, '/');
        }
        return self::absoluteUrl($path);
    }

    protected static function merge(array $values): void
    {
        foreach ($values as $key => $value) {
            if ($value === null || $value === '') {
                continue;
            }
            self::$data[$key] = is_string($value) ? self::sanitize($value) : $value;
        }
    }

    /**
     * Returns the canonical base URL, preferring APP_URL from .env
     * to prevent Host Header Injection attacks.
     */
    private static function trustedBase(): string
    {
        $appUrl = \Core\System\Env::get('APP_URL', '');
        if ($appUrl !== '') {
            return rtrim($appUrl, '/');
        }
        // Fallback: use SERVER_NAME (less spoofable than HTTP_HOST)
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        $host   = $_SERVER['SERVER_NAME'] ?? ($_SERVER['HTTP_HOST'] ?? '');
        return rtrim($scheme . '://' . $host, '/');
    }

    protected static function currentUrl(): string
    {
        $uri   = $_SERVER['REQUEST_URI'] ?? '/';
        $parts = parse_url($uri);
        $path  = $parts['path'] ?? '/';
        if ($path !== '/') {
            $path = rtrim($path, '/');
        }
        $query = !empty($parts['query']) ? '?' . $parts['query'] : '';
        return self::trustedBase() . $path . $query;
    }

    public static function absoluteUrl(string $path): string
    {
        $path = trim($path);
        if ($path === '') {
            return self::currentUrl();
        }

        if (preg_match('#^https?://#i', $path)) {
            return $path;
        }

        $base = self::trustedBase();
        if ($base === '') {
            return $path;
        }

        return $base . '/' . ltrim($path, '/');
    }

    protected static function sanitize(string $value): string
    {
        return trim(strip_tags($value));
    }
}
