<?php

/**
 * Robots & Indexing Module
 *
 * @package ProRank\SEO\Modules\TechnicalSEO
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\TechnicalSEO;

use ProRank\SEO\Modules\BaseModule;
use ProRank\SEO\Core\Config\Settings;
use ProRank\SEO\Core\SettingsManager;
use ProRank\SEO\Core\LicenseManager;
use ProRank\SEO\Core\NotificationManager;
use ProRank\SEO\Services\IndexNowService;

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


/**
 * Class RobotsIndexingModule
 *
 * Handles robots.txt editing and IndexNow API
 */


class RobotsIndexingModule extends BaseModule {
    /**
     * Module slug
     *
     * @var string
     */
    protected string $slug = 'robots-indexing';
    
    /**
     * Module name
     *
     * @var string
     */
    protected string $name = 'Robots & Indexing';
    
    /**
     * Module description
     *
     * @var string
     */
    protected string $description = 'Manage robots.txt and search engine indexing';
    
    /**
     * Required tier
     *
     * @var string
     */
    protected string $feature_tier = 'free';
    
    /**
     * Parent module
     *
     * @var string|null
     */
    protected ?string $parent_slug = 'technical-seo';

    /**
     * License manager instance
     *
     * @var LicenseManager|null
     */
    private ?LicenseManager $license_manager = null;

    /**
     * Notification manager instance
     *
     * @var NotificationManager|null
     */
    private ?NotificationManager $notification_manager = null;

    /**
     * Initialize module
     *
     * @return void
     */
    public function init(): void {
        parent::init();
        
        // Try to get manager instances
        try {
            $this->license_manager = $this->plugin()->license();
            $this->notification_manager = $this->plugin()->notifications();
        } catch (\Exception $e) {
            // Managers not available, skip initialization
            return;
        }

        // Hook into WordPress
        $this->init_hooks();
    }

    /**
     * Initialize hooks
     *
     * @return void
     */
    public function init_hooks(): void {
        $settings = $this->get_settings();
        
        // Robots.txt editor
        if (!empty($settings['enable_robots_editor'])) {
            add_filter('robots_txt', [$this, 'filter_robots_txt'], 10, 2);
        }
        
        // IndexNow
        if (!empty($settings['enable_indexnow'])) {
            add_action('save_post', [$this, 'handle_indexnow_submission'], 20, 3);
            add_action('transition_post_status', [$this, 'handle_post_status_transition'], 10, 3);
        }
        
        // Content Safeguard - Meta tags (Free tier)
        if (!empty($settings['enable_noai_meta']) || !empty($settings['enable_noimageai_meta'])) {
            add_filter('wp_robots', [$this, 'add_content_safeguard_robots'], 10);
        }
        
        // Content Safeguard - Rule-based noindex
        if (!empty($settings['enable_rule_noindex'])) {
            add_filter('wp_robots', [$this, 'apply_rule_based_noindex'], 20);
        }
        
        // Global Noindex settings
        add_filter('wp_robots', [$this, 'apply_global_noindex'], 15);
        
        // Advanced meta directives (2025 features)
        add_filter('wp_robots', [$this, 'apply_advanced_directives'], 25);
        
        // X-Robots-Tag HTTP headers
        if (!empty($settings['enable_x_robots_tag'])) {
            add_action('send_headers', [$this, 'send_x_robots_headers']);
        }
    }

    /**
     * Filter robots.txt output
     *
     * @param string $output  The robots.txt output
     * @param bool   $public  Whether the site is public
     * @return string Modified robots.txt output
     */
    public function filter_robots_txt(string $output, bool $public): string {
        // Only modify if site is public
        if (!$public) {
            return $output;
        }

        // Check if physical robots.txt exists
        $home_path = function_exists('prorank_get_home_path')
            ? (string) prorank_get_home_path()
            : '';
        if ($home_path === '') {
            if ( ! function_exists( 'get_home_path' ) ) {
                require_once ABSPATH . 'wp-admin/includes/file.php';
            }
            $home_path = (string) get_home_path();
        }
        $robots_path = trailingslashit(wp_normalize_path($home_path)) . 'robots.txt';
        if (file_exists($robots_path)) {
            return $output; // Don't override physical file
        }

        // Get saved rules
        $settings = $this->get_settings();
        $custom_rules = $settings['robots_txt_rules'] ?? '';
        
        if (!empty($custom_rules)) {
            $output = $custom_rules . "\n\n";
        }
        
        // Add crawl budget optimization rules (2025 feature)
        $crawl_budget_rules = $this->get_crawl_budget_rules();
        if (!empty($crawl_budget_rules)) {
            $output .= $crawl_budget_rules . "\n";
        }
        
        // Add AI bot blocking if enabled
        if (!empty($settings['block_ai_bots'])) {
            $output .= $this->get_ai_bot_blocking_rules() . "\n\n";
        }
        
        // Add sitemap URL if sitemaps are enabled
        if ($this->is_module_active('sitemaps')) {
            $filename = sanitize_file_name((string) Settings::get('modules.sitemaps.sitemap_index_url', Settings::get('sitemaps_sitemap_index_url', 'sitemap_index.xml')));
            if (!preg_match('/^[A-Za-z0-9_-]+\.xml$/', $filename)) {
                $filename = 'sitemap_index.xml';
            }

            $sitemap_url = home_url('/' . ltrim($filename, '/'));
            $sitemap_alias_url = home_url('/sitemap.xml');
            $normalized_output = strtolower($output);

            if (strpos($normalized_output, strtolower($sitemap_url)) === false && strpos($normalized_output, strtolower($sitemap_alias_url)) === false) {
                $output .= "\nSitemap: " . $sitemap_url . "\n";
            }
        }
        
        return $output;
    }

    /**
     * Handle IndexNow submission on post save
     *
     * @param int     $post_id     Post ID
     * @param WP_Post $post        Post object
     * @param bool    $update      Whether this is an update
     * @return void
     */
    public function handle_indexnow_submission(int $post_id, \WP_Post $post, bool $update): void {
        if ( \ProRank\SEO\Plugin::is_elementor_builder_save_request() ) {
            return;
        }

        // Skip if not an update or post isn't published
        if (!$update || $post->post_status !== 'publish') {
            return;
        }

        // Skip autosaves and revisions
        if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
            return;
        }

        $this->submit_to_indexnow(get_permalink($post_id));
    }

    /**
     * Handle post status transitions for IndexNow
     *
     * @param string  $new_status  New post status
     * @param string  $old_status  Old post status
     * @param WP_Post $post        Post object
     * @return void
     */
    public function handle_post_status_transition(string $new_status, string $old_status, \WP_Post $post): void {
        // Only submit when transitioning to publish
        if ($new_status !== 'publish' || $old_status === 'publish') {
            return;
        }

        $this->submit_to_indexnow(get_permalink($post->ID));
    }

    /**
     * Submit URL to IndexNow API
     *
     * @param string $url URL to submit
     * @return void
     */
    private function submit_to_indexnow(string $url): void {
        $settings = $this->get_settings();
        $api_key = $settings['indexnow_api_key'] ?? '';
        
        if (empty($api_key)) {
            return;
        }

        // Use the IndexNow service
        $indexnow = new IndexNowService($api_key);
        
        // Create key file if it doesn't exist
        $indexnow->create_key_file();
        
        // Submit URL (defaults to Bing endpoint which shares with other engines)
        $success = $indexnow->submit_url($url);
        
        if (!$success) {
            $error = $indexnow->get_last_error();
            
            if ($this->notification_manager) {
                $this->notification_manager->add_notice(
                    'indexnow_error',
                    $error ?: __('IndexNow submission failed', 'prorank-seo'),
                    'error',
                    true
                );
            }
            
            // Log error for debugging
            prorank_log('[ProRank SEO] IndexNow submission failed: ' . ($error ?: 'Unknown error'));
        } else {
            // Log success if debug mode is on
            if (defined('WP_DEBUG') && WP_DEBUG) {
                prorank_log('[ProRank SEO] Successfully submitted URL to IndexNow: ' . $url);
            }
        }
    }

    /**
     * Save robots.txt rules
     *
     * @param string $rules Robots.txt rules
     * @return bool Success status
     */
    public function save_robots_rules(string $rules): bool {
        $settings = $this->get_settings();
        $settings['robots_txt_rules'] = sanitize_textarea_field($rules);
        
        return $this->plugin()->settings()->update('robots_indexing', $settings);
    }

    /**
     * Get module settings
     *
     * @return array
     */
    private function get_settings(): array {
        $settings = $this->plugin()->settings()->get('robots_indexing', [
            'enable_robots_editor' => false,
            'robots_txt_rules' => '',
            'block_ai_bots' => false,
            'enable_indexnow' => false,
            'indexnow_api_key' => '',
            'enable_noai_meta' => false,
            'enable_noimageai_meta' => false,
            'enable_rule_noindex' => false,
            'rule_min_words' => 300,
            'rule_max_age_days' => 0,
            'noindex_posts' => false,
            'noindex_pages' => false,
            'noindex_attachments' => true,
            'noindex_author' => false,
            'noindex_date' => true,
            'noindex_category' => false,
            'noindex_tag' => false,
            'noindex_search' => true,
            'noindex_404' => true,
            'noindex_paginated' => false,
            'enable_x_robots_tag' => false,
        ]);

        return $settings;
    }

    /**
     * Check if another module is active
     *
     * @param string $module_slug Module slug
     * @return bool
     */
    private function is_module_active(string $module_slug): bool {
        $module_manager = $this->plugin()->modules();
        return $module_manager ? $module_manager->is_active($module_slug) : false;
    }

    /**
     * Get module details
     *
     * @return array
     */
    public function get_details(): array {
        return [
            'name'        => __('Robots & Indexing', 'prorank-seo'),
            'description' => __('Manage robots.txt and IndexNow for faster indexing.', 'prorank-seo'),
            'tier'        => 'free',
            'parent'      => 'technical-seo',
        ];
    }

    /**
     * Check if module meets requirements
     *
     * @return bool
     */
    public function meets_requirements(): bool {
        return true;
    }
    
    /**
     * Get AI bot blocking rules
     *
     * @return string
     */
    private function get_ai_bot_blocking_rules(): string {
        $ai_bots = [
            // OpenAI & ChatGPT (2025 updated)
            'GPTBot',
            'ChatGPT-User',
            'CCBot',
            'OAI-SearchBot',  // New OpenAI search bot
            
            // Google AI (2025)
            'Google-Extended',
            'Gemini-Bot',  // Google Gemini
            'Bard-Bot',    // Google Bard
            'GoogleOther', // Google's general AI crawler
            
            // Anthropic AI (2025)
            'Anthropic-AI',
            'Claude-Web',
            'ClaudeBot',
            
            // Microsoft AI (2025)
            'Bingbot-Extended',  // Bing AI features
            'MSNBot-AI',
            
            // Meta/Facebook AI
            'FacebookBot',
            'Meta-ExternalAgent',
            'Meta-AI',
            
            // Amazon AI
            'Amazonbot',
            'Alexa-AI',
            
            // Apple AI (2025)
            'Applebot-Extended',
            'Siri-Bot',
            
            // Other Major AI Services (2025)
            'PerplexityBot',
            'cohere-ai',
            'YouBot',        // You.com AI
            'Neeva-Bot',     // Neeva AI search
            'PiplBot',       // Pipl AI
            
            // Image & Media AI (2025)
            'Bytespider',
            'Diffbot',
            'img2dataset',
            'Scrapy',
            'MidJourney-Bot',
            'StableDiffusion-Bot',
            'DALL-E-Bot',
            
            // AI Research & Training (2025)
            'AI2Bot',
            'CommonCrawl',
            'omgili',
            'omgilibot',
            'DataForSeoBot',
            'ia_archiver',
            'SemrushBot-AI',
            'AhrefsBot-AI',
            
            // Language Model Training (2025)
            'LLM-Crawler',
            'ML-Bot',
            'Dataset-Bot',
            'Training-Bot',
        ];
        
        $rules = "# Block AI/ML Training Bots\n";
        foreach ($ai_bots as $bot) {
            $rules .= "User-agent: {$bot}\n";
            $rules .= "Disallow: /\n\n";
        }
        
        // Add image-specific protection if enabled
        $image_module = $this->plugin()->modules()->get_module('image_optimization');
        if ($image_module && $image_module->get_setting('no_ai_training', false)) {
            $rules .= "# Protect images from AI training\n";
            $rules .= "User-agent: *\n";
            $rules .= "Disallow: /wp-content/uploads/\n";
            $rules .= "Allow: /wp-content/uploads/woocommerce_uploads/\n\n";
            
            // Add AI-specific image crawlers
            $image_crawlers = [
                'img2dataset',
                'Bytespider',
                'CCBot',
                'Diffbot',
                'FacebookBot',
                'Google-Extended',
                'omgilibot',
            ];
            
            $rules .= "# Block AI image crawlers specifically\n";
            foreach ($image_crawlers as $crawler) {
                $rules .= "User-agent: {$crawler}\n";
                $rules .= "Disallow: /wp-content/uploads/\n";
                $rules .= "Crawl-delay: 86400\n\n";
            }
        }
        
        return $rules;
    }
    
    /**
     * Check if AI protection is enabled
     *
     * @return bool
     */
    public function is_ai_protection_enabled(): bool {
        $settings = $this->get_settings();
        return !empty($settings['block_ai_bots']);
    }
    
    /**
     * Add Content Safeguard robots meta tags
     *
     * @param array $robots Robots directives
     * @return array Modified robots directives
     */
    public function add_content_safeguard_robots(array $robots): array {
        $settings = $this->get_settings();
        
        // Add noai directive if enabled
        if (!empty($settings['enable_noai_meta'])) {
            $robots['noai'] = true;
        }
        
        // Add noimageai directive if enabled
        if (!empty($settings['enable_noimageai_meta'])) {
            $robots['noimageai'] = true;
        }
        
        return $robots;
    }
    
    /**
     * Apply rule-based noindex for thin content
     *
     * @param array $robots Robots directives
     * @return array Modified robots directives
     */
    public function apply_rule_based_noindex(array $robots): array {
        // Only apply on singular pages
        if (!is_singular()) {
            return $robots;
        }

        // Never noindex the front page or posts page
        if (is_front_page() || is_home()) {
            return $robots;
        }

        // Skip rule-based noindex for WooCommerce products (they rely on structured data, not text content)
        if (function_exists('is_product') && is_product()) {
            return $robots;
        }

        $settings = $this->get_settings();
        $post = get_post();

        if (!$post) {
            return $robots;
        }

        // Check minimum word count
        $min_words = intval($settings['rule_min_words'] ?? 300);
        if ($min_words > 0) {
            $content = wp_strip_all_tags($post->post_content);
            $word_count = str_word_count($content);

            if ($word_count < $min_words) {
                $robots['noindex'] = true;
                return $robots;
            }
        }
        
        // Check maximum post age
        $max_age_days = intval($settings['rule_max_age_days'] ?? 0);
        if ($max_age_days > 0) {
            $post_age_days = (time() - strtotime($post->post_date)) / DAY_IN_SECONDS;
            
            if ($post_age_days > $max_age_days) {
                $robots['noindex'] = true;
                return $robots;
            }
        }
        
        return $robots;
    }
    
    /**
     * Apply global noindex settings
     *
     * @param array $robots Robots directives
     * @return array Modified robots directives
     */
    public function apply_global_noindex(array $robots): array {
        $settings = $this->get_settings();
        
        // Post types
        if (!empty($settings['noindex_posts']) && is_singular('post')) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_pages']) && is_singular('page')) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_attachments']) && is_attachment()) {
            $robots['noindex'] = true;
        }
        
        // Archives
        if (!empty($settings['noindex_author']) && is_author()) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_date']) && is_date()) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_category']) && is_category()) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_tag']) && is_tag()) {
            $robots['noindex'] = true;
        }
        
        // Special pages
        if (!empty($settings['noindex_search']) && is_search()) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_404']) && is_404()) {
            $robots['noindex'] = true;
        }
        
        if (!empty($settings['noindex_paginated']) && is_paged()) {
            $robots['noindex'] = true;
        }
        
        return $robots;
    }
    
    /**
     * Apply advanced meta directives (2025 features)
     *
     * @param array $robots Robots directives
     * @return array Modified robots directives
     */
    public function apply_advanced_directives(array $robots): array {
        $settings = $this->get_settings();
        
        // Max snippet length
        if (!empty($settings['max_snippet'])) {
            $length = intval($settings['max_snippet']);
            if ($length > 0) {
                $robots['max-snippet'] = $length;
            } elseif ($length === -1) {
                $robots['max-snippet'] = -1; // No limit
            }
        }
        
        // Max image preview
        if (!empty($settings['max_image_preview'])) {
            $size = $settings['max_image_preview'];
            if (in_array($size, ['none', 'standard', 'large'], true)) {
                $robots['max-image-preview'] = $size;
            }
        }
        
        // Max video preview
        if (!empty($settings['max_video_preview'])) {
            $seconds = intval($settings['max_video_preview']);
            if ($seconds >= -1) {
                $robots['max-video-preview'] = $seconds;
            }
        }
        
        // Unavailable after date
        if (!empty($settings['unavailable_after']) && is_singular()) {
            $date = $settings['unavailable_after'];
            // Check if it's a valid date
            $timestamp = strtotime($date);
            if ($timestamp && $timestamp > time()) {
                // Format as RFC 850 date
                $robots['unavailable_after'] = gmdate('D, d M Y H:i:s T', $timestamp);
            }
        }
        
        // notranslate directive
        if (!empty($settings['notranslate'])) {
            $robots['notranslate'] = true;
        }
        
        // noimageindex directive
        if (!empty($settings['noimageindex'])) {
            $robots['noimageindex'] = true;
        }
        
        // nositelinkssearchbox directive
        if (!empty($settings['nositelinkssearchbox'])) {
            $robots['nositelinkssearchbox'] = true;
        }
        
        return $robots;
    }
    
    /**
     * Send X-Robots-Tag HTTP headers
     *
     * @return void
     */
    public function send_x_robots_headers(): void {
        // Only send on frontend pages
        if (is_admin() || is_feed() || is_robots() || is_trackback()) {
            return;
        }
        
        $settings = $this->get_settings();
        $headers = [];
        
        // Collect all robots directives
        $robots = [];
        $robots = $this->add_content_safeguard_robots($robots);
        $robots = $this->apply_global_noindex($robots);
        $robots = $this->apply_rule_based_noindex($robots);
        $robots = $this->apply_advanced_directives($robots);
        
        // Convert to X-Robots-Tag format
        foreach ($robots as $directive => $value) {
            if (is_bool($value) && $value) {
                $headers[] = $directive;
            } elseif (!is_bool($value)) {
                $headers[] = $directive . ':' . $value;
            }
        }
        
        // Send headers
        if (!empty($headers)) {
            header('X-Robots-Tag: ' . implode(', ', $headers));
        }
        
        // Send specific headers for file types
        if (!empty($settings['x_robots_file_types'])) {
            $this->send_file_type_headers();
        }
    }
    
    /**
     * Send X-Robots-Tag headers for specific file types
     *
     * @return void
     */
    private function send_file_type_headers(): void {
        $settings = $this->get_settings();
        $request_uri = prorank_get_server_var( 'REQUEST_URI' );
        
        // Check file extension
        $extension = pathinfo($request_uri, PATHINFO_EXTENSION);
        
        if (empty($extension)) {
            return;
        }
        
        // PDF files
        if ($extension === 'pdf' && !empty($settings['noindex_pdf'])) {
            header('X-Robots-Tag: noindex, nofollow');
        }
        
        // Image files
        $image_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'];
        if (in_array($extension, $image_extensions, true) && !empty($settings['noindex_images'])) {
            header('X-Robots-Tag: noimageindex');
        }
        
        // Video files
        $video_extensions = ['mp4', 'webm', 'ogg', 'avi', 'mov'];
        if (in_array($extension, $video_extensions, true) && !empty($settings['noindex_videos'])) {
            header('X-Robots-Tag: noindex');
        }
    }
    
    /**
     * Get crawl budget optimization rules for robots.txt
     *
     * @return string
     */
    public function get_crawl_budget_rules(): string {
        $settings = $this->get_settings();
        $rules = '';
        
        // Block action URLs (cart, checkout, login, etc.)
        if (!empty($settings['block_action_urls'])) {
            $rules .= "# Block action URLs to save crawl budget\n";
            $rules .= "User-agent: *\n";
            $rules .= "Disallow: /*?add-to-cart=*\n";
            $rules .= "Disallow: /*?remove_item=*\n";
            $rules .= "Disallow: /cart/*\n";
            $rules .= "Disallow: /checkout/*\n";
            $rules .= "Disallow: /my-account/*\n";
            $rules .= "Disallow: /*?orderby=*\n";
            $rules .= "Disallow: /*?filter*=*\n";
            $rules .= "Disallow: /*?min_price=*\n";
            $rules .= "Disallow: /*?max_price=*\n\n";
        }
        
        // Block filtered/faceted URLs
        if (!empty($settings['block_filtered_urls'])) {
            $rules .= "# Block filtered URLs to prevent infinite crawl space\n";
            $rules .= "User-agent: *\n";
            $rules .= "Disallow: /*?*filter*\n";
            $rules .= "Disallow: /*?*sort*\n";
            $rules .= "Disallow: /*?*page=*&*\n";
            $rules .= "Disallow: /*?*color=*\n";
            $rules .= "Disallow: /*?*size=*\n";
            $rules .= "Disallow: /*?*brand=*\n\n";
        }
        
        // Block internal search results
        if (!empty($settings['block_search_results'])) {
            $rules .= "# Block internal search results\n";
            $rules .= "User-agent: *\n";
            $rules .= "Disallow: /?s=*\n";
            $rules .= "Disallow: /search/*\n";
            $rules .= "Disallow: /*?*search*\n\n";
        }
        
        // Add crawl-delay warning (not supported by Google)
        if (!empty($settings['show_crawl_delay_warning'])) {
            $rules .= "# Note: crawl-delay is not supported by Googlebot\n";
            $rules .= "# Use Search Console's crawl rate settings instead\n";
            $rules .= "# User-agent: *\n";
            $rules .= "# Crawl-delay: 1\n\n";
        }
        
        return $rules;
    }
}
