<?php

/**
 * Readability REST API Controller
 *
 * Handles readability analysis endpoints.
 *
 * @package ProRank\SEO\Core\RestApi
 * @since   1.0.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\RestApi;

use ProRank\SEO\Core\Content\AnalysisContentCollector;
use ProRank\SEO\Core\Content\InclusiveLanguageAnalyzer;
use ProRank\SEO\Core\Content\ProminentWordsAnalyzer;
use ProRank\SEO\Modules\Content\Readability;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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


/**
 * ReadabilityController class
 */


class ReadabilityController extends BaseController {
    
    /**
     * Constructor
     */
    public function __construct() {
        $this->rest_base = 'readability-score';
    }
    
    /**
     * Register routes
     *
     * @return void
     */
    public function register_routes(): void {
        // GET /readability-score/{post_id}
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/(?P<post_id>\d+)',
            [
                [
                    'methods'             => \WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_readability_score'],
                    'permission_callback' => [$this, 'check_permission_edit_posts'],
                    'args'                => [
                        'post_id' => [
                            'description' => __('Post ID to analyze', 'prorank-seo'),
                            'type'        => 'integer',
                            'required'    => true,
                            'minimum'     => 1,
                        ],
                    ],
                ],
            ]
        );
    }
    
    /**
     * Get readability score for a post
     *
     * @param WP_REST_Request $request Request object.
     * @return WP_REST_Response|WP_Error
     */
    public function get_readability_score(WP_REST_Request $request) {
        return $this->try_callback(function() use ($request) {
            $post_id = (int) $request->get_param('post_id');

            // Get post content
            $post_content = get_post_field('post_content', $post_id, 'raw');
            if (!is_string($post_content)) {
                $post_content = '';
            }

            // Check if post exists
            if (is_wp_error($post_content)) {
                return $this->get_error_response(
                    __('Post not found.', 'prorank-seo'),
                    404,
                    'post_not_found'
                );
            }

            // Task 5 — optionally augment with custom-field/ACF text.
            $collected = class_exists(AnalysisContentCollector::class)
                ? AnalysisContentCollector::collect($post_id, $post_content)
                : ['text' => $post_content, 'custom_fields_included' => false, 'custom_field_count' => 0, 'custom_field_chars' => 0, 'custom_field_truncated' => false];
            $post_content = (string) $collected['text'];

            // Handle empty content
            if (empty($post_content)) {
                return $this->get_success_response([
                    'score' => null,
                    'level' => null,
                    'grade' => null,
                    'message' => __('No content to analyze.', 'prorank-seo'),
                    'custom_fields_included' => $collected['custom_fields_included'],
                    'custom_field_count'     => $collected['custom_field_count'],
                    'custom_field_chars'     => $collected['custom_field_chars'],
                    'inclusive_language'     => $this->build_inclusive_language_payload(''),
                    'prominent_words'        => $this->build_prominent_words_payload(0),
                ]);
            }

            if (!class_exists(Readability::class)) {
                return $this->get_success_response([
                    'score' => null,
                    'level' => null,
                    'grade' => null,
                    'message' => __('Readability engine is unavailable.', 'prorank-seo'),
                    'custom_fields_included' => $collected['custom_fields_included'],
                    'custom_field_count'     => $collected['custom_field_count'],
                    'custom_field_chars'     => $collected['custom_field_chars'],
                    'inclusive_language'     => $this->build_inclusive_language_payload(''),
                    'prominent_words'        => $this->build_prominent_words_payload(0),
                ]);
            }

            // Strip HTML tags and clean content
            $cleaned_content = $this->clean_content($post_content);
            
            // Calculate readability score
            $score = Readability::calculate_flesch_kincaid($cleaned_content);
            
            // Prepare response data
            $response_data = [
                'score' => $score,
                'level' => null,
                'grade' => null,
                'stats' => null,
            ];
            
            if ($score !== null) {
                $response_data['level'] = Readability::get_readability_level($score);
                $response_data['grade'] = Readability::get_grade_level($score);

                // Count stats
                $word_count = str_word_count($cleaned_content);
                $sentence_count = preg_match_all('/[.!?]+/', $cleaned_content, $matches);
                $paragraph_count = preg_match_all('/\n\s*\n/', $post_content, $matches) + 1;

                // Add stats for UI display
                $response_data['stats'] = [
                    'word_count' => $word_count,
                    'sentence_count' => max(1, $sentence_count),
                    'paragraph_count' => max(1, $paragraph_count),
                    'estimated_reading_time' => $this->estimate_reading_time($cleaned_content),
                ];
            }

            // Task 5 — surface read-only flags so the editor can show the
            // user that custom fields contributed to the score.
            $response_data['custom_fields_included'] = $collected['custom_fields_included'];
            $response_data['custom_field_count']     = $collected['custom_field_count'];
            $response_data['custom_field_chars']     = $collected['custom_field_chars'];

            // Task 7 — additive inclusive-language summary. Always present in
            // the response (so the UI can render Pass when count is 0); the
            // 'enabled' flag tells the UI whether to surface the section.
            $response_data['inclusive_language'] = $this->build_inclusive_language_payload($post_content);

            // Task 8 — additive prominent-words payload. Reads from the index
            // meta written by the save_post handler; stays a stable shape so
            // the UI does not need to guard for partial keys.
            $response_data['prominent_words'] = $this->build_prominent_words_payload($post_id);

            return $this->get_success_response($response_data);
        });
    }
    
    /**
     * Clean content for analysis
     *
     * Removes HTML tags, shortcodes, and excessive whitespace.
     *
     * @param string $content Raw post content.
     * @return string Cleaned content.
     */
    private function clean_content(string $content): string {
        // Strip shortcodes
        $content = strip_shortcodes($content);
        
        // Strip HTML tags
        $content = wp_strip_all_tags($content);
        
        // Decode HTML entities
        $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
        
        // Remove multiple spaces and normalize whitespace
        $content = preg_replace('/\s+/', ' ', $content);
        
        // Trim
        $content = trim($content);
        
        return $content;
    }
    
    /**
     * Estimate reading time
     *
     * @param string $content Cleaned content.
     * @return int Estimated minutes to read.
     */
    private function estimate_reading_time(string $content): int {
        // Average reading speed: 200-250 words per minute
        // We'll use 225 as a middle ground
        $words_per_minute = 225;
        
        // Count words
        $word_count = str_word_count($content);
        
        // Calculate reading time in minutes
        $reading_time = ceil($word_count / $words_per_minute);
        
        return max(1, (int) $reading_time);
    }

    /**
     * Task 7 — build the inclusive-language slice of the readability response.
     *
     * Always returns a stable shape so the UI can render "Pass" cleanly even
     * when the analyzer is disabled or the content is empty. Never blocks
     * the rest of the response on analyzer errors.
     */
    private function build_inclusive_language_payload(string $content): array {
        $settings = InclusiveLanguageAnalyzer::get_settings();
        $payload = [
            'enabled'         => (bool) $settings['enabled'],
            'total_issues'    => 0,
            'severity_counts' => ['high' => 0, 'medium' => 0, 'low' => 0],
            'issues'          => [],
            'truncated'       => false,
        ];
        if (!$settings['enabled'] || $content === '') {
            return $payload;
        }
        $result = InclusiveLanguageAnalyzer::analyze($content, [
            'ignored_terms' => $settings['ignored_terms'],
        ]);
        $payload['total_issues']    = (int) $result['total_issues'];
        $payload['severity_counts'] = $result['severity_counts'];
        $payload['issues']          = $result['issues'];
        $payload['truncated']       = (bool) $result['truncated'];
        return $payload;
    }

    /**
     * Task 8 — prominent-words slice of the readability response. Stable
     * shape (always returns enabled/indexed/terms/stale/version) so the UI
     * does not need to defensively guard for partial keys.
     */
    private function build_prominent_words_payload(int $post_id): array {
        $stub = [
            'enabled' => false,
            'indexed' => false,
            'stale'   => false,
            'version' => ProminentWordsAnalyzer::ANALYZER_VERSION,
            'terms'   => [],
        ];
        if (!class_exists(ProminentWordsAnalyzer::class)) {
            return $stub;
        }
        if ($post_id <= 0) {
            $stub['enabled'] = (bool) ProminentWordsAnalyzer::get_settings()['enabled'];
            return $stub;
        }
        return ProminentWordsAnalyzer::get_post_index($post_id);
    }
}
