<?php

/**
 * Context Analyzer
 *
 * Analyzes context around phrases for better link placement
 *
 * @package ProRank\SEO\Modules\Content\InternalLinking\Parser
 * @since   1.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Content\InternalLinking\Parser;

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


/**
 * ContextAnalyzer class
 */


class ContextAnalyzer {
    
    /**
     * Content parser instance
     *
     * @var ContentParser
     */
    private ContentParser $parser;
    
    /**
     * Context window size (words)
     *
     * @var int
     */
    private const CONTEXT_WINDOW = 15;
    
    /**
     * Constructor
     */
    public function __construct() {
        $this->parser = new ContentParser();
    }
    
    /**
     * Analyze context quality for link placement
     *
     * @param string $content Full content
     * @param string $phrase  Phrase to analyze
     * @param string $target_url Target URL for the link
     * @return array Analysis results
     */
    public function analyze_link_context(string $content, string $phrase, string $target_url): array {
        $context = $this->parser->extract_context($content, $phrase, self::CONTEXT_WINDOW);
        
        if (empty($context['sentence'])) {
            return [
                'suitable' => false,
                'score' => 0,
                'reasons' => ['Phrase not found in content'],
            ];
        }
        
        $analysis = [
            'suitable' => true,
            'score' => 0,
            'reasons' => [],
            'context' => $context,
        ];
        
        // Check for existing links nearby
        if ($this->has_nearby_links($context)) {
            $analysis['score'] -= 0.2;
            $analysis['reasons'][] = 'Other links nearby';
        }
        
        // Check sentence quality
        $sentence_quality = $this->analyze_sentence_quality($context['sentence']);
        $analysis['score'] += $sentence_quality['score'];
        $analysis['sentence_quality'] = $sentence_quality;
        
        // Check semantic relevance
        $relevance = $this->calculate_semantic_relevance($context, $target_url);
        $analysis['score'] += $relevance;
        $analysis['relevance_score'] = $relevance;
        
        // Check position in content
        $position_score = $this->calculate_position_score($content, $context['position']);
        $analysis['score'] += $position_score;
        $analysis['position_score'] = $position_score;
        
        // Normalize score
        $analysis['score'] = max(0, min(1, $analysis['score']));
        $analysis['suitable'] = $analysis['score'] > 0.3;
        
        return $analysis;
    }
    
    /**
     * Find best context for a phrase
     *
     * @param string $content Content to search
     * @param string $phrase  Phrase to find
     * @return array Best context found
     */
    public function find_best_context(string $content, string $phrase): array {
        $sentences = $this->parser->parse_sentences($content);
        $best_context = null;
        $best_score = 0;
        
        foreach ($sentences as $sentence) {
            if (stripos($sentence['text'], $phrase) === false) {
                continue;
            }
            
            $context = $this->parser->extract_context($content, $phrase);
            $quality = $this->analyze_sentence_quality($sentence['text']);
            
            $score = $quality['score'];
            
            // Prefer sentences without existing links
            if (!$sentence['has_links']) {
                $score += 0.3;
            }
            
            // Prefer longer sentences (more context)
            if ($sentence['word_count'] > 15 && $sentence['word_count'] < 40) {
                $score += 0.2;
            }
            
            if ($score > $best_score) {
                $best_score = $score;
                $best_context = [
                    'context' => $context,
                    'sentence' => $sentence,
                    'score' => $score,
                ];
            }
        }
        
        return $best_context ?: [
            'context' => $this->parser->extract_context($content, $phrase),
            'sentence' => null,
            'score' => 0,
        ];
    }
    
    /**
     * Generate anchor text variations
     *
     * @param string $phrase       Original phrase
     * @param array  $context      Context data
     * @param string $target_title Target page title
     * @return array Anchor text variations
     */
    public function generate_anchor_variations(string $phrase, array $context, string $target_title): array {
        $variations = [
            ['text' => $phrase, 'type' => 'exact', 'score' => 1.0],
        ];
        
        // Use target title if appropriate
        if (strlen($target_title) <= 50 && $this->is_natural_anchor($target_title)) {
            $variations[] = [
                'text' => $target_title,
                'type' => 'title',
                'score' => 0.9,
            ];
        }
        
        // Create shortened version
        $words = preg_split('/\s+/', $phrase);
        if (count($words) > 3) {
            $shortened = implode(' ', array_slice($words, 0, 3));
            if ($this->is_natural_anchor($shortened)) {
                $variations[] = [
                    'text' => $shortened,
                    'type' => 'shortened',
                    'score' => 0.8,
                ];
            }
        }
        
        // Extract key terms from context
        $key_terms = $this->extract_key_terms($context['sentence'] ?? '');
        foreach ($key_terms as $term) {
            if (stripos($phrase, $term) !== false && $term !== $phrase) {
                $variations[] = [
                    'text' => $term,
                    'type' => 'key_term',
                    'score' => 0.7,
                ];
            }
        }
        
        // Remove duplicates
        $unique_variations = [];
        $seen = [];
        foreach ($variations as $variation) {
            $key = strtolower($variation['text']);
            if (!isset($seen[$key])) {
                $seen[$key] = true;
                $unique_variations[] = $variation;
            }
        }
        
        return $unique_variations;
    }
    
    /**
     * Check if context has nearby links
     *
     * @param array $context Context data
     * @return bool
     */
    private function has_nearby_links(array $context): bool {
        $text = $context['before'] . ' ' . $context['phrase'] . ' ' . $context['after'];
        return preg_match('/<a[^>]+href[^>]*>/i', $text) === 1;
    }
    
    /**
     * Analyze sentence quality
     *
     * @param string $sentence Sentence to analyze
     * @return array Quality metrics
     */
    private function analyze_sentence_quality(string $sentence): array {
        $quality = [
            'score' => 0.5,
            'metrics' => [],
        ];
        
        $word_count = str_word_count($sentence);
        
        // Length score
        if ($word_count >= 10 && $word_count <= 30) {
            $quality['score'] += 0.2;
            $quality['metrics']['length'] = 'optimal';
        } elseif ($word_count < 10) {
            $quality['score'] -= 0.1;
            $quality['metrics']['length'] = 'too_short';
        } else {
            $quality['score'] -= 0.05;
            $quality['metrics']['length'] = 'too_long';
        }
        
        // Readability indicators
        if (!preg_match('/[.!?]$/', trim($sentence))) {
            $quality['score'] -= 0.1;
            $quality['metrics']['complete'] = false;
        }
        
        // Check for questions (good for linking)
        if (preg_match('/\?/', $sentence)) {
            $quality['score'] += 0.1;
            $quality['metrics']['has_question'] = true;
        }
        
        // Check for action words
        $action_words = ['learn', 'discover', 'find', 'explore', 'read', 'see', 'check'];
        foreach ($action_words as $word) {
            if (stripos($sentence, $word) !== false) {
                $quality['score'] += 0.1;
                $quality['metrics']['has_action_word'] = true;
                break;
            }
        }
        
        return $quality;
    }
    
    /**
     * Calculate semantic relevance
     *
     * @param array  $context    Context data
     * @param string $target_url Target URL
     * @return float Relevance score
     */
    private function calculate_semantic_relevance(array $context, string $target_url): float {
        // Extract keywords from URL
        $url_parts = wp_parse_url($target_url);
        $path = $url_parts['path'] ?? '';
        $url_keywords = preg_split('/[-_\/]/', $path);
        $url_keywords = array_filter($url_keywords);
        
        // Check for keyword matches in context
        $context_text = strtolower($context['before'] . ' ' . $context['after']);
        $matches = 0;
        
        foreach ($url_keywords as $keyword) {
            if (strlen($keyword) > 3 && stripos($context_text, $keyword) !== false) {
                $matches++;
            }
        }
        
        return min(0.3, $matches * 0.1);
    }
    
    /**
     * Calculate position score
     *
     * @param string $content  Full content
     * @param int    $position Position in content
     * @return float Position score
     */
    private function calculate_position_score(string $content, int $position): float {
        $content_length = strlen($content);
        if ($content_length === 0) {
            return 0;
        }
        
        $relative_position = $position / $content_length;
        
        // Prefer links in the first 75% of content
        if ($relative_position < 0.25) {
            return 0.2;
        } elseif ($relative_position < 0.75) {
            return 0.3;
        } else {
            return 0.1;
        }
    }
    
    /**
     * Check if text makes a natural anchor
     *
     * @param string $text Text to check
     * @return bool
     */
    private function is_natural_anchor(string $text): bool {
        // Check length
        if (strlen($text) < 2 || strlen($text) > 60) {
            return false;
        }
        
        // Check for stop words only
        $words = preg_split('/\s+/', strtolower($text));
        $stop_words = ['the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at'];
        
        $non_stop_words = array_diff($words, $stop_words);
        if (empty($non_stop_words)) {
            return false;
        }
        
        return true;
    }
    
    /**
     * Extract key terms from text
     *
     * @param string $text Text to analyze
     * @return array Key terms
     */
    private function extract_key_terms(string $text): array {
        $terms = [];
        
        // Extract capitalized phrases (likely important)
        if (preg_match_all('/\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*\b/', $text, $matches)) {
            foreach ($matches[0] as $match) {
                if (strlen($match) > 3) {
                    $terms[] = $match;
                }
            }
        }
        
        // Extract quoted phrases
        if (preg_match_all('/"([^"]+)"/', $text, $matches)) {
            foreach ($matches[1] as $match) {
                if (strlen($match) > 3 && strlen($match) < 50) {
                    $terms[] = $match;
                }
            }
        }
        
        return array_unique($terms);
    }
}