<?php
/**
 * Enhanced Internal Linking with Extractive-Only AI
 * Prevents hallucinations by forcing AI to only select exact text that exists
 *
 * @package ContentPerformanceAnalyzer
 * @since 2.0.0
 */

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

class CPAP_Interlinking {
    
    /**
     * Initialize the interlinking system
     */
    public static function init() {
        // AJAX handlers for suggestions and applying links
        add_action('wp_ajax_cpanalyzer_get_interlink_suggestions', array(__CLASS__, 'get_suggestions'));
        add_action('wp_ajax_cpanalyzer_apply_interlinks', array(__CLASS__, 'apply_interlinks'));
    }

    /**
     * AJAX handler to get extractive-only link suggestions
     */
    public static function get_suggestions() {
        check_ajax_referer('cpanalyzer_interlinking_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error( array( 'message' => __( 'Forbidden', 'content-performance-analyzer' ) ), 403 );
        }

        $source_post_id = intval($_POST['source_post_id'] ?? 0);
        $target_post_id = intval($_POST['target_post_id'] ?? 0);

        // Validate inputs
        if (!$source_post_id || !$target_post_id) {
            wp_send_json_error( array( 'message' => __( 'Invalid post IDs', 'content-performance-analyzer' ) ) );
        }

        // Only work with published content to prevent linking to drafts
        $source_post = get_post($source_post_id);
        $target_post = get_post($target_post_id);
        
        if (!$source_post || $source_post->post_status !== 'publish') {
            wp_send_json_success(array('candidates' => array()));
        }
        
        if (!$target_post || $target_post->post_status !== 'publish') {
            wp_send_json_success(array('candidates' => array()));
        }

        // Load helper functions
        require_once CPANALYZER_PLUGIN_DIR . 'includes/cpa-interlink-utils.php';

        // Extract and normalize plain text from posts
        $source_plain = cpanalyzer_interlink_get_plain_text($source_post_id);
        $target_plain = cpanalyzer_interlink_get_plain_text($target_post_id);
        $source_norm = cpanalyzer_interlink_normalize($source_plain);
        $target_norm = cpanalyzer_interlink_normalize($target_plain);

        // Generate deterministic candidates (prevents hallucination)
        $candidates = cpanalyzer_interlink_generate_candidates($source_norm, get_the_title($target_post_id));

        // Ask AI to RANK candidates only (no free-text generation)
        $ranked_candidates = self::rank_candidates_with_ai(array(
            'source_url' => get_permalink($source_post_id),
            'source_title' => get_the_title($source_post_id),
            'target_url' => get_permalink($target_post_id),
            'target_title' => get_the_title($target_post_id),
            'source_text' => mb_substr($source_norm, 0, 4000), // Limit to prevent token overflow
            'target_text' => mb_substr($target_norm, 0, 4000),
            'candidate_list' => $candidates,
        ));

        // CRITICAL: Hard validate every suggestion before returning
        $valid_candidates = array();
        foreach ($ranked_candidates as $candidate) {
            if (cpanalyzer_interlink_validate_anchor($source_norm, $candidate['anchor_text'], $candidate['start'], $candidate['end'])) {
                $valid_candidates[] = $candidate;
            } else {
                // Log invalid candidates for debugging
                self::debug_log('[CPANALYZER Interlinking] INVALID CANDIDATE: ' . json_encode($candidate));
            }
        }

        wp_send_json_success(array(
            'candidates' => array_slice($valid_candidates, 0, 10), // Limit to top 10
            'source_post_id' => $source_post_id,
            'target_post_id' => $target_post_id,
            'source_title' => get_the_title($source_post_id),
            'target_title' => get_the_title($target_post_id),
            'target_url' => get_permalink($target_post_id)
        ));
    }

    /**
     * AJAX handler to apply selected links
     */
    public static function apply_interlinks() {
        check_ajax_referer('cpanalyzer_interlinking_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Forbidden', 'content-performance-analyzer')), 403);
        }

        $source_post_id = intval($_POST['source_post_id'] ?? 0);
        $target_url = isset($_POST['target_url']) ? esc_url_raw(wp_unslash($_POST['target_url'])) : '';
        $items_json = isset($_POST['items']) ? sanitize_textarea_field(wp_unslash($_POST['items'])) : '[]';
        $items = json_decode($items_json, true);

        // Validate inputs
        if (!$source_post_id || !$target_url || !is_array($items)) {
            wp_send_json_error(array('message' => __('Invalid request parameters', 'content-performance-analyzer')), 400);
        }

        // Check user can edit this post
        if (!current_user_can('edit_post', $source_post_id)) {
            wp_send_json_error(array('message' => __('Cannot edit this post', 'content-performance-analyzer')), 403);
        }

        require_once CPANALYZER_PLUGIN_DIR . 'includes/cpa-interlink-utils.php';

        // Get fresh content and rebuild blocks (avoid stale offset issues)
        $post_content = get_post_field('post_content', $source_post_id);
        
        // Ensure parse_blocks function is available
        if (!function_exists('parse_blocks')) {
            wp_send_json_error(array('message' => __('Block parsing not available. Please ensure WordPress 5.0+ is installed.', 'content-performance-analyzer')), 500);
        }
        
        $blocks = parse_blocks($post_content);
        $source_text = cpanalyzer_interlink_get_plain_text($source_post_id);
        $source_norm = cpanalyzer_interlink_normalize($source_text);

        $applied = array();
        $skipped = array();

        // Process each selected link
        foreach ($items as $item) {
            // Re-validate anchor text and offsets against fresh content
            $is_valid = cpanalyzer_interlink_validate_anchor(
                $source_norm, 
                $item['anchor_text'], 
                intval($item['start']), 
                intval($item['end'])
            );

            if (!$is_valid) {
                $skipped[] = $item;
                self::debug_log('[CPANALYZER Interlinking] SKIPPED: Invalid anchor in fresh content - ' . $item['anchor_text']);
                continue;
            }

            // Try to insert the link into blocks
            $link_inserted = cpanalyzer_interlink_insert_link_into_blocks($blocks, $item['anchor_text'], $target_url);
            
            if ($link_inserted) {
                $applied[] = $item;
                self::debug_log('[CPANALYZER Interlinking] APPLIED: ' . $item['anchor_text'] . ' -> ' . $target_url);
            } else {
                $skipped[] = $item;
                self::debug_log('[CPANALYZER Interlinking] SKIPPED: Could not insert link for - ' . $item['anchor_text']);
            }
        }

        // Update post content if any links were applied
        if (!empty($applied)) {
            // Ensure serialize_blocks function is available
            if (!function_exists('serialize_blocks')) {
                wp_send_json_error(array('message' => __('Block serialization not available. Please ensure WordPress 5.0+ is installed.', 'content-performance-analyzer')), 500);
            }
            
            $new_content = serialize_blocks($blocks);
            $update_result = wp_update_post(array(
                'ID' => $source_post_id,
                'post_content' => $new_content,
            ));

            if (is_wp_error($update_result)) {
                wp_send_json_error(array(
                    'message' => sprintf(
                        /* translators: %s: wp_update_post error message */
                        __('Failed to update post: %s', 'content-performance-analyzer'),
                        $update_result->get_error_message()
                    )
                ));
            }

            // Clear cache to ensure fresh content
            clean_post_cache($source_post_id);
        }

        wp_send_json_success(array(
            'applied' => $applied,
            'skipped' => $skipped,
            'message' => sprintf(
                /* translators: 1: number of links applied; 2: number of links skipped */
                __('Applied %1$d links successfully. %2$d skipped.', 'content-performance-analyzer'),
                count($applied),
                count($skipped)
            )
        ));
    }

    /**
     * Use AI to rank pre-generated candidates (extractive-only approach)
     * 
     * @param array $payload Data for AI analysis
     * @return array Ranked candidates with confidence scores
     */
    private static function rank_candidates_with_ai($payload) {
        // Check if AI processor is available
        if (!class_exists('CPAP_AI_Processor')) {
            self::debug_log('[CPANALYZER Interlinking] AI processor not available, returning unranked candidates');
            return $payload['candidate_list'];
        }

        try {
            $ai_processor = new CPAP_AI_Processor();
            
            if (!$ai_processor->is_configured()) {
                self::debug_log('[CPANALYZER Interlinking] AI processor not configured');
                return $payload['candidate_list'];
            }

            // Create extractive-only prompt that only allows selection from candidates
            $prompt = self::create_extractive_prompt($payload);
            
            $response = $ai_processor->call_openai_api($prompt, array(
                'max_tokens' => 1000,
                'temperature' => 0.000001, // CRITICAL: Near-zero randomness to prevent hallucinations
                'top_p' => 0.1      // Very focused responses
            ));

            if (empty($response)) {
                return $payload['candidate_list'];
            }

            // Parse AI response
            $ai_selections = json_decode($response, true);
            
            if (!is_array($ai_selections)) {
                self::debug_log('[CPANALYZER Interlinking] Invalid AI response: ' . $response);
                return $payload['candidate_list'];
            }

            // Map AI selections back to candidates
            $ranked = array();
            foreach ($ai_selections as $selection) {
                if (!isset($selection['id'])) continue;
                
                // Find the candidate by ID
                foreach ($payload['candidate_list'] as $candidate) {
                    if ($candidate['id'] === $selection['id']) {
                        $candidate['confidence'] = $selection['confidence'] ?? 0.5;
                        $candidate['reason'] = $selection['reason'] ?? '';
                        $ranked[] = $candidate;
                        break;
                    }
                }
            }

            return $ranked;

        } catch (Exception $e) {
            self::debug_log('[CPANALYZER Interlinking] AI ranking error: ' . $e->getMessage());
            return $payload['candidate_list'];
        }
    }

    /**
     * Protected debug logging method
     * 
     * @param string $message Debug message to log
     */
    private static function debug_log($message) {
        if (defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Protected debug logging
            error_log($message);
        }
    }

    /**
     * Create extractive-only prompt that prevents hallucinations
     * 
     * @param array $payload Data for prompt creation
     * @return string AI prompt
     */
    private static function create_extractive_prompt($payload) {
        $candidate_list_text = '';
        foreach ($payload['candidate_list'] as $candidate) {
            $candidate_list_text .= sprintf(
                "- ID: %s, Text: \"%s\", Position: %d-%d\n",
                $candidate['id'],
                $candidate['anchor_text'],
                $candidate['start'],
                $candidate['end']
            );
        }

        return sprintf(
            "You are an extractive text selector for internal linking. You may ONLY select from the provided candidate list.\n\n" .
            "TASK: Select 2-4 candidates from the list below that would make good internal links from the source to the target.\n\n" .
            "SOURCE PAGE:\n" .
            "Title: \"%s\"\n" .
            "URL: %s\n" .
            "Content: \"%s\"\n\n" .
            "TARGET PAGE:\n" .
            "Title: \"%s\"\n" .
            "URL: %s\n" .
            "Content: \"%s\"\n\n" .
            "CANDIDATE LIST (you MUST only select from these):\n%s\n\n" .
            "CRITICAL RULES:\n" .
            "1. You can ONLY select candidates from the list above using their exact ID\n" .
            "2. You CANNOT modify, create, or suggest any text not in the candidate list\n" .
            "3. Select candidates that are contextually relevant to the target page\n" .
            "4. Return ONLY valid JSON with this exact structure:\n\n" .
            "[\n" .
            "  {\n" .
            "    \"id\": \"candidate_id_from_list\",\n" .
            "    \"confidence\": 0.8,\n" .
            "    \"reason\": \"brief explanation why this is a good link\"\n" .
            "  }\n" .
            "]\n\n" .
            "If no candidates are suitable, return an empty array: []\n" .
            "Return only the JSON array, no other text.",
            $payload['source_title'],
            $payload['source_url'],
            $payload['source_text'],
            $payload['target_title'],
            $payload['target_url'],
            $payload['target_text'],
            $candidate_list_text
        );
    }
}
