<?php
/**
 * Tam Rank™ SEO Audit
 */

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

class TamRank_SEO_Audit
{

    public function __construct()
    {
        add_action('wp_ajax_tam_rank_seo_audit', array($this, 'ajax_seo_audit'));
    }

    /**
     * Audit a specific post
     * Uses same algorithm as meta box live score for consistency
     */
    /**
     * Audit a specific post
     * Uses centralized TamRank_Meta_Calculator for consistency
     */
    public function audit_post($post)
    {
        // Collect data
        $focus_keyword = (string) get_post_meta($post->ID, '_tam_rank_focus_keyword', true);
        $meta_title = (string) get_post_meta($post->ID, '_tam_rank_meta_title', true);
        $meta_description = (string) get_post_meta($post->ID, '_tam_rank_meta_description', true);
        $custom_slug = (string) get_post_meta($post->ID, '_tam_rank_custom_slug', true);

        // Fallbacks
        if (empty($meta_title)) {
            $meta_title = isset($post->post_title) ? (string) $post->post_title : '';
        }
        $slug = $custom_slug !== '' ? $custom_slug : (isset($post->post_name) ? (string) $post->post_name : '');

        // Perform analysis
        $data = [
            'title' => $meta_title,
            'description' => $meta_description,
            'focus_keyword' => $focus_keyword,
            'slug' => $slug
        ];

        // Use the centralized calculator
        if (class_exists('TamRank_Meta_Calculator')) {
            $analysis = TamRank_Meta_Calculator::analyze($data);
            $overall_score = $analysis['total_score'];
            $details = $analysis['details'];
        } else {
            // Should not happen, but safe fallback
            $overall_score = 0;
            $details = [];
        }

        // Generate recommendations
        $recommendations = $this->generate_recommendations($details);

        return array(
            'score' => $overall_score,
            'overall_score' => $overall_score, // For backward compatibility
            'details' => $details,
            'recommendations' => $recommendations
        );
    }


    // Obsolete methods removed (logic moved to TamRank_Meta_Calculator)


    /**
     * Check H1 tags
     */
    private function check_h1_tags($content, $focus_keyword)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        // Count H1 tags
        preg_match_all('/<h1[^>]*>(.*?)<\/h1>/is', $content, $h1_matches);
        $h1_count = count($h1_matches[0]);

        // Check H1 count (5 points)
        if ($h1_count === 1) {
            $score += 5;
        } elseif ($h1_count === 0) {
            $issues[] = __('No H1 heading found', 'tam-rank');
            $passed = false;
            $score += 0;
        } else {
            $issues[] = sprintf( /* translators: %d: number of H1 headings */ __('Multiple H1 headings found (%d)', 'tam-rank'), $h1_count );
            $score += 2;
            $passed = false;
        }

        // Check if focus keyword is in H1 (5 points)
        if ($h1_count > 0 && $focus_keyword) {
            $h1_text = wp_strip_all_tags($h1_matches[1][0]);
            if (TamRank_Meta_Calculator::keyword_exists($h1_text, $focus_keyword)) {
                $score += 5;
            } else {
                $issues[] = __('Focus keyword not in H1', 'tam-rank');
                $score += 1;
                $passed = false;
            }
        } elseif ($h1_count > 0) {
            $score += 3; // No keyword set, partial credit
        }

        return array(
            'name' => __('H1 Heading', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'h1_count' => $h1_count,
            'h1_text' => $h1_count > 0 ? wp_strip_all_tags($h1_matches[1][0]) : ''
        );
    }

    /**
     * Check image alt tags
     */
    private function check_image_alt_tags($content)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        // Find all images
        preg_match_all('/<img[^>]+>/i', $content, $img_matches);
        $total_images = count($img_matches[0]);

        if ($total_images === 0) {
            return array(
                'name' => __('Alt Tags', 'tam-rank'),
                'score' => 10, // Full score if no images
                'passed' => true,
                'issues' => array(),
                'total_images' => 0,
                'missing_alt' => 0
            );
        }

        $missing_alt = 0;

        foreach ($img_matches[0] as $img) {
            if (!preg_match('/alt\s*=\s*["\'][^"\']*["\']/', $img) || preg_match('/alt\s*=\s*["\']["\']/', $img)) {
                $missing_alt++;
            }
        }

        $alt_percentage = (($total_images - $missing_alt) / $total_images) * 100;

        if ($alt_percentage === 100) {
            $score = 10;
        } elseif ($alt_percentage >= 80) {
            $score = 7;
            $issues[] = sprintf( /* translators: 1: number of images missing alt text, 2: total number of images */ __('%1$d of %2$d images are missing alt text', 'tam-rank'), $missing_alt, $total_images );
            $passed = false;
        } elseif ($alt_percentage >= 50) {
            $score = 4;
            $issues[] = sprintf( /* translators: 1: number of images missing alt text, 2: total number of images */ __('%1$d of %2$d images are missing alt text', 'tam-rank'), $missing_alt, $total_images );
            $passed = false;
        } else {
            $score = 1;
            $issues[] = __('More than half of the images are missing alt text', 'tam-rank');
            $passed = false;
        }

        return array(
            'name' => __('Alt Tags', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'total_images' => $total_images,
            'missing_alt' => $missing_alt
        );
    }

    /**
     * Check internal links
     */
    private function check_internal_links($content, $post_id)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        $site_url = home_url();

        // Find all links
        preg_match_all('/<a[^>]+href\s*=\s*["\']([^"\']+)["\'][^>]*>/i', $content, $link_matches);

        $internal_links = 0;

        foreach ($link_matches[1] as $href) {
            // Skip current post
            if (strpos($href, '?p=' . $post_id) !== false || strpos($href, '/' . get_post_field('post_name', $post_id)) !== false) {
                continue;
            }

            // Check if internal link
            if (strpos($href, $site_url) === 0 || (strpos($href, '/') === 0 && strpos($href, '//') !== 0)) {
                $internal_links++;
            }
        }

        if ($internal_links >= 3) {
            $score = 10;
        } elseif ($internal_links >= 1) {
            $score = 6;
            $issues[] = sprintf( /* translators: %d: number of internal links */ __('Few internal links (%d)', 'tam-rank'), $internal_links );
            $passed = false;
        } else {
            $score = 0;
            $issues[] = __('No internal links found', 'tam-rank');
            $passed = false;
        }

        return array(
            'name' => __('Internal Links', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'internal_links' => $internal_links
        );
    }

    /**
     * Check content length
     */
    private function check_content_length($content)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        // Extract body content if it's full HTML
        if (preg_match('/<body[^>]*>(.*?)<\/body>/is', $content, $body_matches)) {
            $content = $body_matches[1];
        }

        // Remove scripts, styles, and other non-content elements
        $content = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $content);
        $content = preg_replace('/<style[^>]*>.*?<\/style>/is', '', $content);
        $content = preg_replace('/<nav[^>]*>.*?<\/nav>/is', '', $content);
        $content = preg_replace('/<header[^>]*>.*?<\/header>/is', '', $content);
        $content = preg_replace('/<footer[^>]*>.*?<\/footer>/is', '', $content);

        $text = wp_strip_all_tags($content);
        $word_count = str_word_count($text);

        if ($word_count >= 300) {
            $score = 10;
        } elseif ($word_count >= 200) {
            $score = 7;
            $issues[] = sprintf( /* translators: %d: word count */ __('Content is fairly short (%d words, recommended: 300+)', 'tam-rank'), $word_count );
            $passed = false;
        } elseif ($word_count >= 100) {
            $score = 4;
            $issues[] = sprintf( /* translators: %d: word count */ __('Content is short (%d words, recommended: 300+)', 'tam-rank'), $word_count );
            $passed = false;
        } else {
            $score = 1;
            $issues[] = sprintf( /* translators: %d: word count */ __('Content is too short (%d words, minimum: 300)', 'tam-rank'), $word_count );
            $passed = false;
        }

        return array(
            'name' => __('Word Count', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'word_count' => $word_count
        );
    }

    /**
     * Check keyword density
     */
    private function check_keyword_density($content, $focus_keyword)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        if (empty($focus_keyword)) {
            return array(
                'name' => __('Keyword Density', 'tam-rank'),
                'score' => 5, // Neutral score if no focus keyword
                'passed' => true,
                'issues' => array(__('No focus keyword set', 'tam-rank')),
                'density' => 0,
                'keyword_count' => 0
            );
        }

        // Extract body content if it's full HTML
        if (preg_match('/<body[^>]*>(.*?)<\/body>/is', $content, $body_matches)) {
            $content = $body_matches[1];
        }

        // Remove scripts, styles, and other non-content elements
        $content = preg_replace('/<script[^>]*>.*?<\/script>/is', '', $content);
        $content = preg_replace('/<style[^>]*>.*?<\/style>/is', '', $content);
        $content = preg_replace('/<nav[^>]*>.*?<\/nav>/is', '', $content);
        $content = preg_replace('/<header[^>]*>.*?<\/header>/is', '', $content);
        $content = preg_replace('/<footer[^>]*>.*?<\/footer>/is', '', $content);

        $text = wp_strip_all_tags($content);
        $word_count = str_word_count($text);

        // Count keyword occurrences (case-insensitive)
        $keyword_count = TamRank_Meta_Calculator::keyword_count($text, $focus_keyword);

        $density = $word_count > 0 ? ($keyword_count / $word_count) * 100 : 0;

        if ($density >= 0.5 && $density <= 2.5) {
            $score = 10;
        } elseif ($density > 0 && $density < 0.5) {
            $score = 5;
            $issues[] = sprintf( /* translators: %s: keyword density percentage */ __('Keyword density too low (%s%%, recommended: 0.5-2.5%%)', 'tam-rank'), round($density, 2) );
            $passed = false;
        } elseif ($density > 2.5) {
            $score = 4;
            $issues[] = sprintf( /* translators: %s: keyword density percentage */ __('Keyword density too high (%s%%, risk of keyword stuffing)', 'tam-rank'), round($density, 2) );
            $passed = false;
        } else {
            $score = 0;
            $issues[] = __('Keyword not found in content', 'tam-rank');
            $passed = false;
        }

        return array(
            'name' => __('Keyword Density', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'density' => round($density, 2),
            'keyword_count' => $keyword_count
        );
    }

    /**
     * Check outbound links
     */
    private function check_outbound_links($content)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        $site_url = home_url();

        // Find all links
        preg_match_all('/<a[^>]+href\s*=\s*["\']([^"\']+)["\'][^>]*>/i', $content, $link_matches);

        $outbound_links = 0;

        foreach ($link_matches[1] as $href) {
            // Check if external link
            if (strpos($href, 'http') === 0 && strpos($href, $site_url) === false) {
                $outbound_links++;
            }
        }

        if ($outbound_links >= 1 && $outbound_links <= 3) {
            $score = 10;
        } elseif ($outbound_links === 0) {
            $score = 7;
            $issues[] = __('No external links found', 'tam-rank');
            $passed = false;
        } else {
            $score = 6;
            $issues[] = sprintf( /* translators: %d: number of external links */ __('Many external links (%d)', 'tam-rank'), $outbound_links );
            $passed = false;
        }

        return array(
            'name' => __('External Links', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'outbound_links' => $outbound_links
        );
    }

    /**
     * Generate recommendations based on audit results
     */
    private function generate_recommendations($details)
    {
        $recommendations = array();

        // Check each detail for issues
        foreach ($details as $check => $result) {
            // Ensure result has required keys
            if (!isset($result['passed']) || !isset($result['issues'])) {
                continue;
            }

            if (!$result['passed'] && !empty($result['issues'])) {
                $check_name = isset($result['name']) ? $result['name'] : ucfirst(str_replace('_', ' ', $check));
                foreach ($result['issues'] as $issue) {
                    $recommendations[] = $check_name . ': ' . $issue;
                }
            }
        }

        // Add general recommendations
        if (empty($recommendations)) {
            $recommendations[] = __('Great! Your page scores well on all SEO aspects.', 'tam-rank');
        } else {
            $recommendations[] = __('Improve the points above for a better SEO score.', 'tam-rank');
        }

        return $recommendations;
    }

    /**
     * AJAX handler for SEO audit
     */
    public function ajax_seo_audit()
    {
        check_ajax_referer('tam_rank_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => tamrank__('error_permission_denied', 'You do not have permission for this action.'), 'code' => 'permission_denied'));
        }

        $url = sanitize_url(wp_unslash($_POST['url'] ?? ''));

        if (empty($url)) {
            wp_send_json_error(array('message' => tamrank__('error_url_required', 'Enter a URL to test.'), 'code' => 'missing_parameter'));
        }

        // Fetch page content. SSRF-safe: tam_rank_safe_remote_get() validates the
        // user-supplied URL (scheme + private/reserved-IP block) and caps redirects
        // so the server cannot be made to probe internal targets.
        $response = tam_rank_safe_remote_get($url);

        if (is_wp_error($response)) {
            wp_send_json_error(array('message' => sprintf(tamrank__('error_fetch_url', 'Could not fetch URL: %s'), $response->get_error_message()), 'code' => 'request_failed'));
        }

        $content = wp_remote_retrieve_body($response);

        if (empty($content)) {
            wp_send_json_error(array('message' => tamrank__('error_no_content', 'No content found at this URL.'), 'code' => 'not_found'));
        }

        // Parse HTML for audit
        $results = $this->audit_html_content($content, $url);

        wp_send_json_success($results);
    }

    /**
     * Audit HTML content from URL
     */
    /**
     * Audit HTML content from URL
     */
    private function audit_html_content($html, $url)
    {
        $score = 0;
        $details = array();

        // Extract title
        preg_match('/<title[^>]*>(.*?)<\/title>/i', $html, $title_matches);
        $title = isset($title_matches[1]) ? trim(wp_strip_all_tags($title_matches[1])) : '';

        // Extract meta description
        preg_match('/<meta[^>]+name\s*=\s*["\']description["\'][^>]+content\s*=\s*["\']([^"\']*)["\'][^>]*>/i', $html, $desc_matches);
        $description = isset($desc_matches[1]) ? trim($desc_matches[1]) : '';

        // Use Central Calculator for Meta Checks
        if (class_exists('TamRank_Meta_Calculator')) {
            $meta_analysis = TamRank_Meta_Calculator::analyze([
                'title' => $title,
                'description' => $description,
                'focus_keyword' => '', // We don't know the keyword in URL audit
                'slug' => '' // We ignore slug check here or parse from URL?
            ]);

            // Add Title Score
            $details['meta_title'] = $meta_analysis['details']['meta_title'];
            $score += $meta_analysis['details']['meta_title']['score'];

            // Add Description Score
            $details['meta_description'] = $meta_analysis['details']['meta_description'];
            $score += $meta_analysis['details']['meta_description']['score'];
        } else {
            $score += 0;
        }

        // Continue with Content Checks (Local logic)
        $h1_check = $this->check_h1_tags($html, '');
        $details['h1_tags'] = $h1_check;
        $score += $h1_check['score'];

        $alt_check = $this->check_image_alt_tags($html);
        $details['alt_tags'] = $alt_check;
        $score += $alt_check['score'];

        // Get body content for text analysis
        preg_match('/<body[^>]*>(.*?)<\/body>/is', $html, $body_matches);
        $body_content = isset($body_matches[1]) ? $body_matches[1] : $html;

        $length_check = $this->check_content_length($body_content);
        $details['content_length'] = $length_check;
        $score += $length_check['score'];

        $links_check = $this->check_internal_links_html($body_content, $url);
        $details['internal_links'] = $links_check;
        $score += $links_check['score'];

        $outbound_check = $this->check_outbound_links($body_content);
        $details['outbound_links'] = $outbound_check;
        $score += $outbound_check['score'];

        // Calculate overall score (Max score is roughly 30 (meta) + 40 (content) = 70)
        // Note: Meta Calculator gives 15+15=30. H1=10, Alt=10, Len=10, Int=10, Out=10. Total 80?
        // Let's keep the denominator roughly consistent or calculate dynamic max.
        // H1(10) + Alt(10) + Len(10) + Int(10) + Out(10) = 50.
        // Meta(30) + Content(50) = 80.
        // Previous denominator was 70. Let's use 80 for accuracy if max scores line up.
        // To be safe and compatible with previous strictness, 70 is fine (slightly easier to get 100).
        $overall_score = min(100, round(($score / 70) * 100));

        $recommendations = $this->generate_recommendations($details);

        return array(
            'overall_score' => $overall_score,
            'details' => $details,
            'recommendations' => $recommendations
        );
    }

    /**
     * Check internal links for HTML content
     */
    private function check_internal_links_html($content, $url)
    {
        $score = 0;
        $issues = array();
        $passed = true;

        $parsed_url = wp_parse_url($url);
        $site_url = $parsed_url['scheme'] . '://' . $parsed_url['host'];

        // Find all links
        preg_match_all('/<a[^>]+href\s*=\s*["\']([^"\']+)["\'][^>]*>/i', $content, $link_matches);

        $internal_links = 0;

        foreach ($link_matches[1] as $href) {
            // Skip current page
            if ($href === $url || $href === wp_parse_url($url, PHP_URL_PATH)) {
                continue;
            }

            // Check if internal link
            if (strpos($href, $site_url) === 0 || (strpos($href, '/') === 0 && strpos($href, '//') !== 0)) {
                $internal_links++;
            }
        }

        if ($internal_links >= 3) {
            $score = 10;
        } elseif ($internal_links >= 1) {
            $score = 6;
            $issues[] = sprintf( /* translators: %d: number of internal links */ __('Few internal links (%d)', 'tam-rank'), $internal_links );
            $passed = false;
        } else {
            $score = 0;
            $issues[] = __('No internal links found', 'tam-rank');
            $passed = false;
        }

        return array(
            'name' => __('Internal Links', 'tam-rank'),
            'score' => $score,
            'passed' => $passed,
            'issues' => $issues,
            'internal_links' => $internal_links
        );
    }
}