<?php

/**
 * Product Category Sitemap Provider
 *
 * Generates sitemaps for WooCommerce product categories.
 *
 * @package ProRank\SEO\Modules\Indexing\Sitemaps
 * @since   2.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Indexing\Sitemaps;

use ProRank\SEO\Core\SettingsManager;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * ProductCategorySitemapProvider class
 */


class ProductCategorySitemapProvider extends BaseSitemapProvider {
    private ?SettingsManager $settings_manager = null;
    
    /**
     * Provider slug
     *
     * @var string
     */
    protected string $slug = 'product_cat';
    
    /**
     * Provider name
     *
     * @var string
     */
    protected string $name = 'Product Categories';
    
    /**
     * Items per page
     *
     * @var int
     */
    protected int $items_per_page = 1000;
    
    /**
     * Check if provider is enabled
     *
     * @return bool
     */
    public function is_enabled(): bool {
        // Check if WooCommerce is active
        if (!class_exists('WooCommerce')) {
            return false;
        }
        
        // Check settings
        $plugin = \ProRank\SEO\Plugin::get_instance();
        $settings_manager = $this->settings_manager ?: $plugin->settings();
        $sitemap_settings = $this->resolve_sitemap_settings($settings_manager);
        
        // Check if WC integration is enabled
        $wc_enabled = $settings_manager->get('enable_wc_sitemap_integration', 'ecommerce_seo', true);
        if (!$wc_enabled) {
            return false;
        }
        
        // Check if product categories are included
        $enabled_taxonomies = $sitemap_settings['include_taxonomies'] ?? ['category', 'post_tag'];

        return in_array('product_cat', $enabled_taxonomies, true)
            && $settings_manager->get('sitemap_include_product_categories', 'ecommerce_seo', true);
    }
    
    /**
     * Get total pages
     *
     * @return int
     */
    public function get_total_pages(): int {
        $terms = get_terms([
            'taxonomy' => 'product_cat',
            'hide_empty' => true,
            'fields' => 'ids',
        ]);
        
        if (is_wp_error($terms)) {
            return 0;
        }
        
        $total_items = count($terms);
        return (int) ceil($total_items / $this->items_per_page);
    }
    
    /**
     * Generate sitemap
     *
     * @param int $page Page number.
     * @return string XML content.
     */
    public function generate(int $page = 1): string {
        $offset = ($page - 1) * $this->items_per_page;
        
        $terms = get_terms([
            'taxonomy' => 'product_cat',
            'hide_empty' => true,
            'orderby' => 'name',
            'order' => 'ASC',
            'number' => $this->items_per_page,
            'offset' => $offset,
        ]);
        
        if (is_wp_error($terms)) {
            $terms = [];
        }
        
        $xml = new \XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        
        // Start XML document
        $xml->startDocument('1.0', 'UTF-8');
        
        // Add promotional comment
        $xml->writeComment(' Generated by ProRank SEO - https://prorank.io ');
        
        // Start urlset
        $xml->startElement('urlset');
        $xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
        $xml->writeAttribute('xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1');
        
        // Add categories
        foreach ($terms as $term) {
            // Skip if excluded by SEO settings
            $noindex = get_term_meta($term->term_id, '_prorank_seo_noindex', true);
            if ($noindex) {
                continue;
            }
            
            $xml->startElement('url');
            
            // Location
            $term_link = get_term_link($term, 'product_cat');
            if (!is_wp_error($term_link)) {
                $xml->writeElement('loc', $term_link);
            }
            
            // Last modified - use most recent product in category
            $lastmod = $this->get_category_lastmod($term->term_id);
            if ($lastmod) {
                $xml->writeElement('lastmod', $lastmod);
            }
            
            // Change frequency
            $xml->writeElement('changefreq', 'weekly');
            
            // Priority based on hierarchy
            $priority = '0.6';
            if ($term->parent === 0) {
                $priority = '0.8'; // Top-level categories get higher priority
            }
            $xml->writeElement('priority', $priority);
            
            // Add category thumbnail if available
            $this->add_category_image($xml, $term);
            
            $xml->endElement(); // url
        }
        
        $xml->endElement(); // urlset
        $xml->endDocument();
        
        return $xml->outputMemory();
    }

    /**
     * Generate XML content for the requested sitemap page.
     *
     * @param int $page Page number.
     * @return string
     */
    public function generate_xml(int $page = 1): string {
        return $this->generate($page);
    }
    
    /**
     * Get last modified date for category
     *
     * @param int $term_id Term ID.
     * @return string|null
     */
    private function get_category_lastmod(int $term_id): ?string {
        // Get most recent product in this category
        $args = [
            'post_type' => 'product',
            'post_status' => 'publish',
            'posts_per_page' => 1,
            'orderby' => 'modified',
            'order' => 'DESC',
            'tax_query' => [
                [
                    'taxonomy' => 'product_cat',
                    'field' => 'term_id',
                    'terms' => $term_id,
                ],
            ],
            'fields' => 'ids',
        ];
        
        $query = new \WP_Query($args);
        
        if ($query->have_posts()) {
            $post_id = $query->posts[0];
            return get_post_modified_time('c', true, $post_id);
        }
        
        return null;
    }
    
    /**
     * Add category image to sitemap
     *
     * @param \XMLWriter $xml XML writer instance.
     * @param \WP_Term $term Term object.
     * @return void
     */
    private function add_category_image(\XMLWriter $xml, \WP_Term $term): void {
        // Get category thumbnail
        $thumbnail_id = get_term_meta($term->term_id, 'thumbnail_id', true);
        
        if (!$thumbnail_id) {
            return;
        }
        
        $image_url = wp_get_attachment_url($thumbnail_id);
        if (!$image_url) {
            return;
        }
        
        $xml->startElement('image:image');
        $xml->writeElement('image:loc', $image_url);
        
        // Add title
        $xml->writeElement('image:title', $this->clean_string($term->name));
        
        // Add caption if description exists
        if (!empty($term->description)) {
            $xml->writeElement('image:caption', $this->clean_string($term->description));
        }
        
        $xml->endElement(); // image:image
    }

    /**
     * Get the most recent modification date for the sitemap page.
     *
     * @param int $page Page number.
     * @return string
     */
    protected function get_last_modified(int $page = 1): string {
        $args = [
            'post_type' => 'product',
            'post_status' => 'publish',
            'posts_per_page' => 1,
            'orderby' => 'modified',
            'order' => 'DESC',
            'tax_query' => [
                [
                    'taxonomy' => 'product_cat',
                    'operator' => 'EXISTS',
                ],
            ],
            'fields' => 'ids',
        ];

        $query = new \WP_Query($args);
        if ($query->have_posts()) {
            return (string) get_post_modified_time('c', true, (int) $query->posts[0]);
        }

        return gmdate('c');
    }
    
    /**
     * Clean string for XML
     *
     * @param string $string String to clean.
     * @return string
     */
    private function clean_string(string $string): string {
        // Remove control characters and ensure valid UTF-8
        $string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $string);
        $string = mb_convert_encoding($string, 'UTF-8', 'UTF-8');
        
        // Escape XML entities
        return htmlspecialchars($string, ENT_XML1 | ENT_QUOTES, 'UTF-8');
    }
    
    /**
     * Get index entries for sitemap index
     *
     * @return array
     */
    public function get_index_entries(): array {
        $entries = [];
        $total_pages = $this->get_total_pages();
        
        for ($page = 1; $page <= $total_pages; $page++) {
            $loc = home_url('product_cat-sitemap' . ($page > 1 ? $page : '') . '.xml');
            
            // Get last modified date from most recent product
            $args = [
                'post_type' => 'product',
                'post_status' => 'publish',
                'posts_per_page' => 1,
                'orderby' => 'modified',
                'order' => 'DESC',
                'fields' => 'ids',
            ];
            
            $query = new \WP_Query($args);
            $lastmod = null;
            
            if ($query->have_posts()) {
                $post_id = $query->posts[0];
                $lastmod = get_post_modified_time('c', true, $post_id);
            }
            
            $entry = ['loc' => $loc];
            if ($lastmod) {
                $entry['lastmod'] = $lastmod;
            }
            
            $entries[] = $entry;
        }
        
        return $entries;
    }
}
