<?php

declare(strict_types=1);

namespace CliqThemes\StoreLocator\Integrations;

defined('ABSPATH') || exit;

/**
 * Yoast SEO integration. On a store-detail URL, points Yoast's title / OG /
 * description / canonical at the store, and registers a dedicated XML sitemap
 * (cliq-stores-sitemap.xml) listing every store-detail URL so they are indexable
 * even though they hang off a single base page rather than real posts.
 */
final class Yoast implements Integration
{
    private const SITEMAP = 'cliq-stores';

    private StoreDetailSeo $seo;

    public function __construct(StoreDetailSeo $seo)
    {
        $this->seo = $seo;
    }

    public function isActive(): bool
    {
        return defined('WPSEO_VERSION');
    }

    public function register(): void
    {
        add_filter('wpseo_title', [$this, 'title']);
        add_filter('wpseo_opengraph_title', [$this, 'name']);
        add_filter('wpseo_metadesc', [$this, 'description']);
        add_filter('wpseo_opengraph_desc', [$this, 'description']);
        add_filter('wpseo_canonical', [$this, 'canonical']);
        add_filter('wpseo_opengraph_url', [$this, 'canonical']);
        add_filter('wpseo_opengraph_image', [$this, 'image']);

        // Custom store-detail sitemap, added to Yoast's sitemap index.
        add_filter('wpseo_sitemap_index', [$this, 'sitemapIndex']);
        add_action('init', [$this, 'registerSitemap'], 20);
    }

    public function title($title)
    {
        return $this->seo->isStoreDetail() ? $this->seo->title($this->separator()) : $title;
    }

    public function name($value)
    {
        return $this->seo->isStoreDetail() ? $this->seo->name() : $value;
    }

    public function description($value)
    {
        $desc = $this->seo->description();
        return ($this->seo->isStoreDetail() && $desc !== '') ? $desc : $value;
    }

    public function canonical($value)
    {
        $url = $this->seo->canonical();
        return ($this->seo->isStoreDetail() && $url !== '') ? $url : $value;
    }

    public function image($value)
    {
        $img = $this->seo->image();
        return ($this->seo->isStoreDetail() && $img !== '') ? $img : $value;
    }

    /** Yoast's configured title separator (e.g. "-", "|"), defaulting to a dash. */
    private function separator(): string
    {
        if (class_exists('\WPSEO_Utils') && method_exists('\WPSEO_Utils', 'get_title_separator')) {
            $sep = trim((string) \WPSEO_Utils::get_title_separator());
            if ($sep !== '') {
                return $sep;
            }
        }

        return '-';
    }

    /** Register the store sitemap + its URL provider with Yoast. */
    public function registerSitemap(): void
    {
        global $wpseo_sitemaps;
        if ($wpseo_sitemaps) {
            $wpseo_sitemaps->register_sitemap(self::SITEMAP, [$this, 'renderSitemap']);
        }
    }

    /** Append a <sitemap> entry pointing at our store sitemap to the index. */
    public function sitemapIndex(string $index): string
    {
        $urls = $this->seo->storeUrls();
        if ($urls === []) {
            return $index;
        }
        $lastmod = '';
        foreach ($urls as $u) {
            if ($u['lastmod'] !== '' && $u['lastmod'] > $lastmod) {
                $lastmod = $u['lastmod'];
            }
        }

        $entry = '<sitemap>' . "\n"
            . '<loc>' . esc_url(home_url('/' . self::SITEMAP . '-sitemap.xml')) . '</loc>' . "\n"
            . ($lastmod !== '' ? '<lastmod>' . esc_html(gmdate('c', strtotime($lastmod))) . '</lastmod>' . "\n" : '')
            . '</sitemap>' . "\n";

        return $index . $entry;
    }

    /** Build + emit the store-detail URL set through Yoast's renderer. */
    public function renderSitemap(): void
    {
        global $wpseo_sitemaps;
        if (! $wpseo_sitemaps) {
            return;
        }
        $output = '';
        foreach ($this->seo->storeUrls() as $u) {
            $entry = ['loc' => $u['loc'], 'chf' => 'weekly', 'pri' => 0.8];
            if ($u['lastmod'] !== '') {
                $entry['mod'] = $u['lastmod'];
            }
            $output .= $wpseo_sitemaps->renderer->sitemap_url($entry);
        }
        if ($output === '') {
            $wpseo_sitemaps->bad_sitemap = true;
            return;
        }

        $xml = '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
            . 'xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" '
            . 'xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n"
            . $output . '</urlset>';

        $wpseo_sitemaps->set_sitemap($xml);
    }
}
