<?php
/**
 * SEO REST Controller
 *
 * Handles SEO audit, keywords, meta description, and GEO scoring operations.
 *
 * @package WP_Agentic_Writer
 */

/**
 * Class WP_Agentic_Writer_Controller_Seo
 *
 * REST controller for SEO operations.
 *
 * @since 0.3.0
 */
class WP_Agentic_Writer_Controller_Seo
{
    /**
     * Sidebar instance for dependency access.
     *
     * @var WP_Agentic_Writer_Gutenberg_Sidebar
     */
    private $sidebar;

    /**
     * Constructor.
     *
     * @since 0.3.0
     * @param WP_Agentic_Writer_Gutenberg_Sidebar $sidebar Sidebar instance.
     */
    public function __construct($sidebar)
    {
        $this->sidebar = $sidebar;
    }

    /**
     * Handle SEO audit request.
     *
     * @since 0.1.0
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_seo_audit($request)
    {
        // Check rate limit.
        $rate_limit = WPAW_Rate_Limiter::check("seo_audit");
        if (is_wp_error($rate_limit)) {
            return $rate_limit;
        }

        $post_id = isset($request["post_id"]) ? (int) $request["post_id"] : 0;
        if ($post_id <= 0) {
            return new WP_Error(
                "invalid_post",
                __("Invalid post ID.", "wp-agentic-writer"),
                ["status" => 400],
            );
        }

        // Check post permission before reading post content/config.
        if (!$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to access this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        $post = get_post($post_id);
        if (!$post) {
            return new WP_Error(
                "post_not_found",
                __("Post not found.", "wp-agentic-writer"),
                ["status" => 404],
            );
        }

        $post_config = $this->sidebar->get_post_config($post_id);
        $content = wp_strip_all_tags($post->post_content);
        $title = $post->post_title;
        $focus_keyword = $post_config["seo_focus_keyword"] ?? "";

        $audit = [
            "score" => 0,
            "checks" => [],
            "keyword_density" => 0,
            "word_count" => 0,
        ];

        // Word count
        $word_count = str_word_count($content);
        $audit["word_count"] = $word_count;

        // Check 1: Content length
        if ($word_count >= 1500) {
            $audit["checks"][] = [
                "name" => "Content length",
                "status" => "good",
                "message" => "Excellent! {$word_count} words (recommended: 1500+)",
            ];
            $audit["score"] += 15;
        } elseif ($word_count >= 800) {
            $audit["checks"][] = [
                "name" => "Content length",
                "status" => "ok",
                "message" => "Good: {$word_count} words (recommended: 1500+)",
            ];
            $audit["score"] += 10;
        } else {
            $audit["checks"][] = [
                "name" => "Content length",
                "status" => "warning",
                "message" => "Short: {$word_count} words (recommended: 800+)",
            ];
            $audit["score"] += 5;
        }

        // Check 2: Focus keyword presence
        if (!empty($focus_keyword)) {
            $keyword_count = substr_count(
                strtolower($content),
                strtolower($focus_keyword),
            );
            $keyword_density =
                $word_count > 0
                    ? round(($keyword_count / $word_count) * 100, 2)
                    : 0;
            $audit["keyword_density"] = $keyword_density;

            // Keyword in title
            if (stripos($title, $focus_keyword) !== false) {
                $audit["checks"][] = [
                    "name" => "Keyword in title",
                    "status" => "good",
                    "message" => "Focus keyword found in title",
                ];
                $audit["score"] += 20;
            } else {
                $audit["checks"][] = [
                    "name" => "Keyword in title",
                    "status" => "warning",
                    "message" => "Focus keyword not found in title",
                ];
            }

            // Keyword density
            if ($keyword_density >= 1 && $keyword_density <= 2.5) {
                $audit["checks"][] = [
                    "name" => "Keyword density",
                    "status" => "good",
                    "message" => "Optimal: {$keyword_density}% (target: 1-2.5%)",
                ];
                $audit["score"] += 20;
            } elseif ($keyword_density > 0 && $keyword_density < 1) {
                $audit["checks"][] = [
                    "name" => "Keyword density",
                    "status" => "ok",
                    "message" => "Low: {$keyword_density}% (target: 1-2.5%)",
                ];
                $audit["score"] += 10;
            } elseif ($keyword_density > 2.5) {
                $audit["checks"][] = [
                    "name" => "Keyword density",
                    "status" => "warning",
                    "message" => "High: {$keyword_density}% - may be over-optimized",
                ];
                $audit["score"] += 5;
            } else {
                $audit["checks"][] = [
                    "name" => "Keyword density",
                    "status" => "error",
                    "message" => "Focus keyword not found in content",
                ];
            }

            // Keyword in first paragraph
            $first_para = substr($content, 0, 500);
            if (stripos($first_para, $focus_keyword) !== false) {
                $audit["checks"][] = [
                    "name" => "Keyword in intro",
                    "status" => "good",
                    "message" => "Focus keyword in first paragraph",
                ];
                $audit["score"] += 15;
            } else {
                $audit["checks"][] = [
                    "name" => "Keyword in intro",
                    "status" => "warning",
                    "message" => "Add focus keyword to first paragraph",
                ];
            }
        } else {
            $audit["checks"][] = [
                "name" => "Focus keyword",
                "status" => "warning",
                "message" => "No focus keyword set",
            ];
        }

        // Check 3: Headings
        $heading_count = preg_match_all(
            "/<!-- wp:heading.*?-->/",
            $post->post_content,
            $matches,
        );
        if ($heading_count >= 3) {
            $audit["checks"][] = [
                "name" => "Subheadings",
                "status" => "good",
                "message" => "{$heading_count} subheadings found",
            ];
            $audit["score"] += 15;
        } elseif ($heading_count >= 1) {
            $audit["checks"][] = [
                "name" => "Subheadings",
                "status" => "ok",
                "message" => "Only {$heading_count} subheading(s) - add more for readability",
            ];
            $audit["score"] += 8;
        } else {
            $audit["checks"][] = [
                "name" => "Subheadings",
                "status" => "warning",
                "message" => "No subheadings found - add H2/H3 headings",
            ];
        }

        // Check 4: Images
        $image_count = preg_match_all(
            "/<!-- wp:image.*?-->/",
            $post->post_content,
            $matches,
        );
        if ($image_count >= 1) {
            $audit["checks"][] = [
                "name" => "Images",
                "status" => "good",
                "message" => "{$image_count} image(s) found",
            ];
            $audit["score"] += 10;
        } else {
            $audit["checks"][] = [
                "name" => "Images",
                "status" => "ok",
                "message" => "No images - consider adding visuals",
            ];
        }

        // Check 5: Meta description
        $meta_desc = $post_config["seo_meta_description"] ?? "";
        if (!empty($meta_desc)) {
            $meta_len = strlen($meta_desc);
            if ($meta_len >= 120 && $meta_len <= 160) {
                $audit["checks"][] = [
                    "name" => "Meta description",
                    "status" => "good",
                    "message" => "Perfect length: {$meta_len} chars (120-160)",
                ];
                $audit["score"] += 5;
            } elseif ($meta_len > 0) {
                $audit["checks"][] = [
                    "name" => "Meta description",
                    "status" => "ok",
                    "message" => "Length: {$meta_len} chars (optimal: 120-160)",
                ];
                $audit["score"] += 3;
            }
        } else {
            $audit["checks"][] = [
                "name" => "Meta description",
                "status" => "warning",
                "message" => "No meta description set",
            ];
        }

        // Check 6: AI-ish writing patterns (heuristic scanner).
        $ai_pattern_result = $this->sidebar->scan_ai_ish_patterns($post->post_content);
        if ($ai_pattern_result["count"] <= 1) {
            $audit["checks"][] = [
                "name" => "AI-ish pattern risk",
                "status" => "good",
                "message" =>
                    "Low risk: no significant AI-style pattern detected",
            ];
            $audit["score"] += 15;
        } elseif ($ai_pattern_result["count"] <= 4) {
            $audit["checks"][] = [
                "name" => "AI-ish pattern risk",
                "status" => "ok",
                "message" => sprintf(
                    "Moderate risk: %d pattern(s) detected. Consider selective human polish.",
                    $ai_pattern_result["count"],
                ),
            ];
            $audit["score"] += 8;
        } else {
            $audit["checks"][] = [
                "name" => "AI-ish pattern risk",
                "status" => "warning",
                "message" => sprintf(
                    "High risk: %d pattern(s) detected. Refine tone for more natural writing.",
                    $ai_pattern_result["count"],
                ),
            ];
            $audit["score"] += 3;
        }
        $audit["ai_ish_pattern_count"] = $ai_pattern_result["count"];
        $audit["ai_ish_pattern_examples"] = $ai_pattern_result["examples"];

        // Cap score at 100
        $audit["score"] = min(100, $audit["score"]);

        // Convert checks to issues for frontend compatibility
        $audit["issues"] = [];
        foreach ($audit["checks"] as $check) {
            if ($check["status"] !== "good") {
                $audit["issues"][] = [
                    "severity" => $check["status"],
                    "message" => $check["name"] . ": " . $check["message"],
                ];
            }
        }

        return new WP_REST_Response($audit, 200);
    }

    /**
     * Handle generate meta description request.
     *
     * @since 0.1.0
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_generate_meta($request)
    {
        $params = $request->get_json_params();
        $post_id = $params["postId"] ?? 0;
        $content = $params["content"] ?? "";
        $title = $params["title"] ?? "";
        $focus_keyword = $params["focusKeyword"] ?? "";
        $chat_history = $params["chatHistory"] ?? [];

        // Check post permission BEFORE reading post content.
        if ($post_id > 0 && !$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to access this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        if (empty($content) && $post_id > 0) {
            $post = get_post($post_id);
            if ($post) {
                $content = wp_strip_all_tags($post->post_content);
                $title = $post->post_title;
            }
        }

        if (empty($content)) {
            return new WP_Error(
                "no_content",
                __(
                    "No content available to generate meta description.",
                    "wp-agentic-writer",
                ),
                ["status" => 400],
            );
        }

        // Get detected language from post meta
        $stored_language = get_post_meta(
            $post_id,
            "_wpaw_detected_language",
            true,
        );
        $post_config = $this->sidebar->get_post_config($post_id);
        $effective_language = $this->sidebar->resolve_language_preference(
            $post_config,
            $stored_language,
        );
        $language_instruction = $this->sidebar->build_language_instruction(
            $effective_language,
            "meta description",
        );

        // Build chat history context if available
        $chat_context = "";
        if (!empty($chat_history) && is_array($chat_history)) {
            $chat_context = "\n\nOriginal discussion context:\n";
            $user_messages = array_filter($chat_history, function ($msg) {
                return isset($msg["role"]) &&
                    "user" === strtolower($msg["role"]);
            });
            $recent_user = array_slice($user_messages, -2);
            foreach ($recent_user as $msg) {
                $content_text = $msg["content"] ?? "";
                if (!empty($content_text)) {
                    $chat_context .=
                        "- " . substr($content_text, 0, 100) . "\n";
                }
            }
        }

        $provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task(
            "clarity",
        );
        $provider = $provider_result->provider;

        $prompt =
            "Generate a compelling meta description for SEO. Requirements:\n";
        $prompt .=
            "- Length: MAXIMUM 155 characters (STRICT - count every character including spaces)\n";
        $prompt .= "- Include a call-to-action or value proposition\n";
        $prompt .= "- Make it enticing for searchers to click\n";
        if (!empty($focus_keyword)) {
            $prompt .= "- MUST include the focus keyword: \"{$focus_keyword}\"\n";
        }
        $prompt .= "\n{$language_instruction}\n";
        $prompt .= $chat_context;
        $prompt .= "\nTitle: {$title}\n";
        $prompt .=
            "\nContent summary (first 500 chars):\n" . substr($content, 0, 500);
        $prompt .=
            "\n\nIMPORTANT: Your response must be 155 characters or less. Count carefully.\nRespond with ONLY the meta description text, no quotes, no explanation.";

        $messages = [
            [
                "role" => "user",
                "content" => $prompt,
            ],
        ];

        $response = $provider->chat($messages, [], "clarity");

        if (is_wp_error($response)) {
            return $response;
        }

        $meta_description = trim($response["content"] ?? "");
        $meta_description = preg_replace(
            '/^["\']|["\']$/',
            "",
            $meta_description,
        );

        // Enforce 155 character limit
        if (strlen($meta_description) > 155) {
            $meta_description = substr($meta_description, 0, 152) . "...";
        }

        // Track cost for meta description generation.
        $cost = $response["cost"] ?? 0;
        if ($cost > 0 && $post_id > 0) {
            $this->sidebar->track_ai_cost(
                $post_id,
                $response["model"] ?? "unknown",
                "meta_description",
                $response["input_tokens"] ?? 0,
                $response["output_tokens"] ?? 0,
                $cost,
                $provider_result,
                "",
                "success",
            );
        }

        return new WP_REST_Response(
            [
                "meta_description" => $meta_description,
                "length" => strlen($meta_description),
                "cost" => $cost,
                "provider_metadata" => $this->sidebar->build_provider_metadata(
                    $provider_result,
                    $response["model"] ?? "",
                ),
            ],
            200,
        );
    }

    /**
     * Handle suggest keywords request.
     *
     * @since 0.1.0
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_suggest_keywords($request)
    {
        $params = $request->get_json_params();
        $post_id = $params["postId"] ?? 0;
        $session_id = $this->sidebar->resolve_or_create_session_id(
            $params["sessionId"] ?? "",
            $post_id,
        );
        $title = $params["title"] ?? "";
        $sections = $params["sections"] ?? [];

        if (empty($title) || empty($sections)) {
            return new WP_Error(
                "missing_data",
                __(
                    "Title and sections are required for keyword suggestions.",
                    "wp-agentic-writer",
                ),
                ["status" => 400],
            );
        }

        // Check post permission before reading post data.
        if ($post_id > 0 && !$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to access this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        // Get detected language from post meta or config
        $stored_language = get_post_meta(
            $post_id,
            "_wpaw_detected_language",
            true,
        );
        $post_config = $this->sidebar->get_post_config($post_id);
        $effective_language = $this->sidebar->resolve_language_preference(
            $post_config,
            $stored_language,
        );

        // Use keyword suggester helper
        $result = WP_Agentic_Writer_Keyword_Suggester::suggest_keywords(
            $title,
            $sections,
            $effective_language,
            $post_id,
        );

        if (is_wp_error($result)) {
            return $result;
        }

        // Persist SEO keyword suggestion summary to session history for future recall.
        if (!empty($session_id)) {
            $reasoning = trim((string) ($result["reasoning"] ?? ""));
            $focus_keyword = (string) ($result["focus_keyword"] ?? "");
            $secondary_keywords = (array) ($result["secondary_keywords"] ?? []);
            $assistant_summary = "SEO Keywords Suggested:\n\n";
            $assistant_summary .= "Focus Keyword: {$focus_keyword}\n\n";
            $assistant_summary .=
                "Secondary Keywords: " . implode(", ", $secondary_keywords);
            if ("" !== $reasoning) {
                $assistant_summary .= "\n\n{$reasoning}";
            }
            $assistant_summary .=
                "\n\nYou can review and edit these in the Config panel before writing.";

            $context_service = WP_Agentic_Writer_Context_Service::get_instance();
            $context_service->add_message($session_id, [
                "role" => "assistant",
                "content" => $assistant_summary,
                "timestamp" => current_time("c"),
            ]);
        }

        return new WP_REST_Response(
            [
                "focus_keyword" => $result["focus_keyword"],
                "secondary_keywords" => $result["secondary_keywords"],
                "reasoning" => $result["reasoning"],
                "cost" => $result["cost"],
                "provider_metadata" => $this->sidebar->build_provider_metadata(
                    $result["provider_result"] ?? null,
                    $result["model"] ?? "",
                ),
            ],
            200,
        );
    }

    /**
     * Handle context summarization request.
     *
     * @since 0.1.0
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_summarize_context($request)
    {
        $params = $request->get_json_params();
        $chat_history = $params["chatHistory"] ?? [];
        $post_id = $params["postId"] ?? 0;
        $session_id = $this->sidebar->resolve_or_create_session_id(
            $params["sessionId"] ?? "",
            $post_id,
        );

        // Check post permission before using postId for cost tracking.
        if ($post_id > 0 && !$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to access this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        if (!empty($session_id)) {
            $context_service = WP_Agentic_Writer_Context_Service::get_instance();
            $session_context = $context_service->get_context(
                $session_id,
                $post_id,
            );
            if (
                !empty($session_context["messages"]) &&
                is_array($session_context["messages"])
            ) {
                $chat_history = $session_context["messages"];
            }
        }

        // Short history doesn't need summarization
        if (empty($chat_history) || count($chat_history) < 4) {
            return new WP_REST_Response(
                [
                    "summary" => "",
                    "use_full_history" => true,
                    "cost" => 0,
                    "tokens_saved" => 0,
                    "session_id" => $session_id,
                    "message_count" => is_array($chat_history)
                        ? count($chat_history)
                        : 0,
                    "source_message_count" => is_array($chat_history)
                        ? count($chat_history)
                        : 0,
                ],
                200,
            );
        }

        // Build history text
        $history_text = "";
        foreach ($chat_history as $msg) {
            $role = ucfirst($msg["role"] ?? "Unknown");
            $content = $msg["content"] ?? "";
            if (!empty($content)) {
                $history_text .= "{$role}: {$content}\n\n";
            }
        }

        // Build summarization prompt
        $prompt = "Summarize this conversation into key points that capture the user's intent and requirements.

Focus on:
- Main topic
- Specific focus areas
- Rejected/excluded topics
- User preferences (tone, audience, etc.)

Keep the summary concise (max 200 words) but preserve critical context.
Write in the same language as the conversation.

Output format:
TOPIC: [main topic]
FOCUS: [what to include]
EXCLUDE: [what to avoid]
PREFERENCES: [any specific requirements]

Conversation:
{$history_text}";

        // Call AI with clarity model for language detection
        $provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task(
            "clarity",
        );
        $provider = $provider_result->provider;
        $messages = [
            [
                "role" => "user",
                "content" => $prompt,
            ],
        ];

        $response = $provider->chat($messages, [], "summarize");

        if (is_wp_error($response)) {
            return $response;
        }

        // Calculate tokens saved
        $original_tokens = count($chat_history) * 500; // Rough estimate
        $summary_tokens = $response["output_tokens"] ?? 100;
        $tokens_saved = $original_tokens - $summary_tokens;
        $summary = $response["content"] ?? "";

        // Track cost
        $cost = $response["cost"] ?? 0;
        if ($cost > 0) {
            $this->sidebar->track_ai_cost(
                $post_id,
                $response["model"] ?? "",
                "summarize",
                $response["input_tokens"] ?? 0,
                $response["output_tokens"] ?? 0,
                $cost,
                $provider_result,
                $session_id,
                "success",
            );
        }

        return new WP_REST_Response(
            [
                "summary" => $summary,
                "use_full_history" => false,
                "cost" => $cost,
                "tokens_saved" => max(0, $tokens_saved),
                "session_id" => $session_id,
                "message_count" => count($chat_history),
                "source_message_count" => count($chat_history),
            ],
            200,
        );
    }

    /**
     * Handle suggest improvements request (proactive AI suggestions).
     *
     * @since 0.2.0
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_suggest_improvements($request)
    {
        $params = $request->get_json_params();
        $post_id = isset($params["postId"]) ? (int) $params["postId"] : 0;
        $suggestion_types = $params["types"] ?? [
            "clarity",
            "depth",
            "structure",
        ];

        if ($post_id <= 0) {
            return new WP_Error(
                "invalid_post",
                __("Valid post ID is required.", "wp-agentic-writer"),
                ["status" => 400],
            );
        }

        // Check post permission before reading post content.
        if (!$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to access this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        // Get post content for analysis
        $post = get_post($post_id);
        if (!$post) {
            return new WP_Error(
                "post_not_found",
                __("Post not found.", "wp-agentic-writer"),
                ["status" => 404],
            );
        }

        $blocks = parse_blocks($post->post_content);
        $plain_content = "";
        $block_count = 0;

        foreach ($blocks as $block) {
            if (
                !empty($block["blockName"]) &&
                0 === strpos($block["blockName"], "core/")
            ) {
                $block_content = "";
                if (
                    "core/paragraph" === $block["blockName"] ||
                    "core/heading" === $block["blockName"]
                ) {
                    $block_content = $block["attrs"]["content"] ?? "";
                } elseif ("core/list" === $block["blockName"]) {
                    $inner_html = $block["innerHTML"] ?? "";
                    $block_content = wp_strip_all_tags($inner_html);
                } else {
                    $block_content = $block["innerHTML"] ?? "";
                    $block_content = wp_strip_all_tags($block_content);
                }

                if (!empty($block_content)) {
                    $plain_content .= $block_content . "\n\n";
                    $block_count++;
                }
            }
        }

        if (empty($plain_content) || $block_count < 3) {
            return new WP_REST_Response(
                [
                    "suggestions" => [],
                    "message" => "Not enough content to analyze yet.",
                ],
                200,
            );
        }

        // Get post config for context
        $post_config = $this->sidebar->get_post_config($post_id);
        $focus_keyword = $post_config["seo_focus_keyword"] ?? "";

        // Build suggestion type instruction
        $type_instruction = "";
        foreach ($suggestion_types as $type) {
            switch ($type) {
                case "clarity":
                    $type_instruction .=
                        "- Identify sentences or paragraphs that are too complex or confusing\n";
                    break;
                case "depth":
                    $type_instruction .=
                        "- Suggest areas where more examples, data, or explanation would improve the content\n";
                    break;
                case "structure":
                    $type_instruction .=
                        "- Identify missing sections or structural improvements needed for the article\n";
                    break;
                case "engagement":
                    $type_instruction .=
                        "- Suggest ways to increase reader engagement (questions, examples, calls to action)\n";
                    break;
                case "seo":
                    if (!empty($focus_keyword)) {
                        $type_instruction .= "- Check keyword '{$focus_keyword}' usage: suggest where to naturally include it\n";
                    }
                    break;
            }
        }

        $system_prompt = "You are an expert content editor providing constructive improvement suggestions.

Analyze the provided article content and suggest 1-3 specific improvements.
{$type_instruction}

IMPORTANT GUIDELINES:
- Be specific about WHERE in the content the issue is (e.g., 'paragraph 3', 'the section about X')
- Be actionable - tell the user WHAT they should change and WHY
- Be concise - each suggestion should be 1-2 sentences max
- Prioritize the most impactful improvements
- NEVER suggest adding fluff or padding - only genuine improvements

Return your response as valid JSON in this format:
{
  'suggestions': [
    {
      'type': 'clarity|depth|structure|engagement|seo',
      'location': 'Brief description of where in the article',
      'issue': 'What the problem is',
      'suggestion': 'What to do instead',
      'priority': 'high|medium|low'
    }
  ],
  'summary': 'One sentence summary of the overall article quality'
}

If the content is already excellent and needs no major improvements, return an empty suggestions array with a positive summary.
Only suggest changes that would genuinely improve the reader's experience or search engine performance.";

        $messages = [
            [
                "role" => "system",
                "content" => $system_prompt,
            ],
            [
                "role" => "user",
                "content" => "Please analyze this article and suggest improvements:\n\n{$plain_content}",
            ],
        ];

        $provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task(
            "clarity",
        );
        $provider = $provider_result->provider;
        $response = $provider->chat($messages, [], "analysis");

        if (is_wp_error($response)) {
            return $response;
        }

        // Track cost with full nine-argument contract including provider attribution.
        $cost = $response["cost"] ?? 0;
        if ($cost > 0) {
            $actual_provider = "unknown";
            if (
                is_object($provider_result) &&
                isset($provider_result->actual_provider)
            ) {
                $actual_provider = $provider_result->actual_provider;
            }

            // Get session ID for this post if available.
            $session_id = "";
            if ($post_id > 0) {
                $manager = WP_Agentic_Writer_Conversation_Manager::get_instance();
                $session = $manager->get_session_by_post_id($post_id);
                if ($session && isset($session["session_id"])) {
                    $session_id = $session["session_id"];
                }
            }

            $this->sidebar->track_ai_cost(
                $post_id,
                $response["model"] ?? "",
                "analysis",
                $response["input_tokens"] ?? 0,
                $response["output_tokens"] ?? 0,
                $cost,
                $actual_provider,
                $session_id,
                "success",
            );
        }

        // Parse JSON from response
        $content = $response["content"] ?? "";
        $suggestions_json = $this->sidebar->extract_json($content);

        if (null === $suggestions_json) {
            // If JSON parsing fails, return a generic success with no suggestions
            return new WP_REST_Response(
                [
                    "suggestions" => [],
                    "message" =>
                        "Analysis complete but suggestions could not be parsed.",
                ],
                200,
            );
        }

        return new WP_REST_Response(
            [
                "suggestions" => $suggestions_json["suggestions"] ?? [],
                "summary" =>
                    $suggestions_json["summary"] ?? "Analysis complete.",
                "cost" => $response["cost"] ?? 0,
                "provider_metadata" => $this->sidebar->build_provider_metadata(
                    $provider_result,
                    $response["model"] ?? "",
                ),
            ],
            200,
        );
    }

    /**
     * Handle multi-pass refinement request.
     *
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_refine_multi_pass($request)
    {
        $params = $request->get_json_params();
        $pass = $params["pass"] ?? "clarity";
        $blocks = $params["blocks"] ?? [];
        $focus_keyword = $params["focusKeyword"] ?? "";
        $post_id = $params["postId"] ?? 0;

        // Check post permission before using postId for cost tracking.
        if ($post_id > 0 && !$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to edit this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        $pass_prompts = [
            "clarity" =>
                "Improve the clarity, readability, and flow of this content. Make sentences clearer, remove ambiguity, and ensure smooth transitions between ideas.",
            "seo" =>
                'Optimize this content for SEO. Naturally incorporate the focus keyword "%s" where appropriate. Ensure good keyword density (1-2.5%), include variations of the keyword, and maintain readability.',
            "quality" =>
                "Enhance the overall quality of this content. Check for grammar, spelling, and punctuation errors. Improve sentence structure and word choice. Ensure consistent tone throughout.",
        ];

        $prompt = $pass_prompts[$pass] ?? $pass_prompts["clarity"];
        if ($pass === "seo" && $focus_keyword) {
            $prompt = sprintf($prompt, $focus_keyword);
        }

        // Extract text from blocks
        $content = "";
        foreach ($blocks as $block) {
            $content .=
                $this->sidebar->extract_block_content_from_attrs(
                    $block["name"] ?? "core/paragraph",
                    $block["attributes"] ?? [],
                ) . "\n\n";
        }

        if (empty(trim($content))) {
            return new WP_Error("empty_content", "No content to refine", [
                "status" => 400,
            ]);
        }

        $provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task(
            "refinement",
        );
        $provider = $provider_result->provider;
        $messages = [
            [
                "role" => "user",
                "content" => $prompt . "\n\nContent to refine:\n\n" . $content,
            ],
        ];

        $response = $provider->chat($messages, [], "refinement");

        if (is_wp_error($response)) {
            // Track failed attempt for observability.
            $this->sidebar->track_ai_cost(
                $post_id,
                WPAW_Model_Registry::get_default_model("refinement"),
                "refine_multi_pass",
                0,
                0,
                0,
                $provider_result,
                "",
                "error",
            );
            return $response;
        }

        // Track cost.
        $this->sidebar->track_ai_cost(
            $post_id,
            $response["model"] ?? "",
            "refine_multi_pass",
            $response["input_tokens"] ?? 0,
            $response["output_tokens"] ?? 0,
            $response["cost"] ?? 0,
            $provider_result,
            "",
            "success",
        );

        return new WP_REST_Response(
            [
                "pass" => $pass,
                "refined_content" => $response["content"] ?? "",
                "cost" => $response["cost"] ?? 0,
                "provider_metadata" => $this->sidebar->build_provider_metadata(
                    $provider_result,
                    $response["model"] ?? "",
                ),
            ],
            200,
        );
    }

    /**
     * Handle article-wide refinement request.
     *
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_refine_article($request)
    {
        // Check rate limit.
        $rate_limit = WPAW_Rate_Limiter::check("refine");
        if (is_wp_error($rate_limit)) {
            return $rate_limit;
        }

        $params = $request->get_json_params();
        $instructions = $params["instructions"] ?? "Improve overall quality";
        $blocks = $params["blocks"] ?? [];
        $post_id = $params["postId"] ?? 0;

        // Extract text from blocks
        $content = "";
        $block_count = 0;
        foreach ($blocks as $block) {
            $block_content = $this->sidebar->extract_block_content_from_attrs(
                $block["name"] ?? "core/paragraph",
                $block["attributes"] ?? [],
            );
            if (!empty(trim($block_content))) {
                $content .=
                    "[Block " .
                    ($block_count + 1) .
                    "]\n" .
                    $block_content .
                    "\n\n";
                $block_count++;
            }
        }

        if (empty(trim($content))) {
            return new WP_Error("empty_content", "No content to refine", [
                "status" => 400,
            ]);
        }

        // Check post permission if post_id is provided.
        if ($post_id > 0 && !$this->sidebar->check_post_permission($post_id)) {
            return new WP_Error(
                "forbidden",
                __(
                    "You do not have permission to edit this post.",
                    "wp-agentic-writer",
                ),
                ["status" => 403],
            );
        }

        $prompt =
            "Review and improve the following article content based on these instructions: " .
            $instructions .
            "\n\n";
        $prompt .=
            "IMPORTANT: Return the improved content preserving all block structure using this exact format:\n";
        $prompt .= "- Start each block with [Block N] on its own line\n";
        $prompt .= "- Keep the same number of blocks as the original\n";
        $prompt .=
            "- Preserve any code blocks, lists, or formatting within each block\n\n";
        $prompt .= "Original content:\n\n" . $content;

        $provider_result = WP_Agentic_Writer_Provider_Manager::get_provider_for_task(
            "refinement",
        );
        $provider = $provider_result->provider;
        $messages = [
            [
                "role" => "user",
                "content" => $prompt,
            ],
        ];

        $response = $provider->chat($messages, [], "refinement");

        if (is_wp_error($response)) {
            // Track failed attempt for observability.
            $this->sidebar->track_ai_cost(
                $post_id,
                WPAW_Model_Registry::get_default_model("refinement"),
                "refine_article",
                0,
                0,
                0,
                $provider_result,
                "",
                "error",
            );
            return $response;
        }

        // Parse response back to blocks format
        $refined_blocks = $this->sidebar->parse_refined_blocks(
            $response["content"] ?? "",
            $block_count,
        );

        // Track cost.
        $this->sidebar->track_ai_cost(
            $post_id,
            $response["model"] ?? "",
            "refine_article",
            $response["input_tokens"] ?? 0,
            $response["output_tokens"] ?? 0,
            $response["cost"] ?? 0,
            $provider_result,
            "",
            "success",
        );

        return new WP_REST_Response(
            [
                "blocks" => $refined_blocks,
                "count" => count($refined_blocks),
                "cost" => $response["cost"] ?? 0,
                "provider_metadata" => $this->sidebar->build_provider_metadata(
                    $provider_result,
                    $response["model"] ?? "",
                ),
            ],
            200,
        );
    }

    /**
     * Handle GEO (Generative Engine Optimization) scoring request.
     *
     * @param WP_REST_Request $request REST request.
     * @return WP_REST_Response|WP_Error Response.
     */
    public function handle_geo_score($request)
    {
        $post_id = isset($request["post_id"]) ? (int) $request["post_id"] : 0;
        if ($post_id <= 0) {
            return new WP_Error("invalid_post", "Invalid post ID", [
                "status" => 400,
            ]);
        }

        $post = get_post($post_id);
        if (!$post) {
            return new WP_Error("post_not_found", "Post not found", [
                "status" => 404,
            ]);
        }

        $post_config = $this->sidebar->get_post_config($post_id);
        $content = wp_strip_all_tags($post->post_content);
        $title = $post->post_title;

        $geo = [
            "score" => 0,
            "max_score" => 100,
            "rating" => "poor",
            "checks" => [],
            "suggestions" => [],
        ];

        $total_checks = 0;
        $total_score = 0;

        // Check 1: Directness - Does the content answer questions directly?
        $total_checks++;
        $directness_indicators = [
            "this article",
            "in this guide",
            "in this post",
            'here\'s how',
            'here\'s what',
            "the best way",
            "how to",
            "step by step",
            "in this tutorial",
            "learn how",
        ];
        $directness_count = 0;
        foreach ($directness_indicators as $indicator) {
            $directness_count += substr_count(strtolower($content), $indicator);
        }

        if ($directness_count >= 2) {
            $geo["checks"][] = [
                "name" => "Directness",
                "status" => "good",
                "message" => "Content provides direct answers",
                "score" => 20,
            ];
            $total_score += 20;
        } elseif ($directness_count >= 1) {
            $geo["checks"][] = [
                "name" => "Directness",
                "status" => "ok",
                "message" =>
                    "Some direct answers found, consider being more explicit",
                "score" => 12,
            ];
            $total_score += 12;
        } else {
            $geo["checks"][] = [
                "name" => "Directness",
                "status" => "warning",
                "message" =>
                    "Content may be too indirect. Add clear intro sentences that directly address the topic.",
                "score" => 5,
            ];
            $total_score += 5;
            $geo["suggestions"][] =
                'Start with a clear statement: "This guide explains how to [topic]" or "In this article, you\'ll learn [benefit]"';
        }

        // Check 2: Structure - Is the content well-organized with clear headings?
        $total_checks++;
        $heading_count = preg_match_all(
            "/<h[1-6][^>]*>/i",
            $post->post_content,
            $matches,
        );
        $paragraph_count = preg_match_all(
            "/<p[^>]*>/i",
            $post->post_content,
            $matches,
        );

        if ($heading_count >= 3 && $paragraph_count >= 5) {
            $geo["checks"][] = [
                "name" => "Structure",
                "status" => "good",
                "message" => "Excellent structure with {$heading_count} headings and {$paragraph_count} paragraphs",
                "score" => 20,
            ];
            $total_score += 20;
        } elseif ($heading_count >= 1) {
            $geo["checks"][] = [
                "name" => "Structure",
                "status" => "ok",
                "message" =>
                    "Basic structure present, consider adding more subheadings",
                "score" => 12,
            ];
            $total_score += 12;
        } else {
            $geo["checks"][] = [
                "name" => "Structure",
                "status" => "warning",
                "message" =>
                    "Content lacks structure. Add clear H2/H3 headings to break up content.",
                "score" => 5,
            ];
            $total_score += 5;
            $geo["suggestions"][] =
                "Add H2 headings every 200-300 words to organize content into scannable sections";
        }

        // Check 3: Authority - Does the content demonstrate expertise?
        $total_checks++;
        $authority_indicators = [
            "experience",
            "years",
            "research",
            "study",
            "according to",
            "expert",
            "professional",
            "certified",
            "proven",
            "tested",
            "verified",
        ];
        $authority_count = 0;
        foreach ($authority_indicators as $indicator) {
            $authority_count += substr_count(strtolower($content), $indicator);
        }

        if ($authority_count >= 3) {
            $geo["checks"][] = [
                "name" => "Authority",
                "status" => "good",
                "message" => "Content demonstrates strong expertise",
                "score" => 20,
            ];
            $total_score += 20;
        } elseif ($authority_count >= 1) {
            $geo["checks"][] = [
                "name" => "Authority",
                "status" => "ok",
                "message" => "Some authority signals present",
                "score" => 12,
            ];
            $total_score += 12;
        } else {
            $geo["checks"][] = [
                "name" => "Authority",
                "status" => "warning",
                "message" =>
                    "Content lacks authority signals. Add experience, research, or expert references.",
                "score" => 5,
            ];
            $total_score += 5;
            $geo["suggestions"][] =
                'Add phrases like "Based on years of experience", "Research shows", or "Experts recommend"';
        }

        // Check 4: Clarity - Is the content easy to understand?
        $total_checks++;
        $word_count = str_word_count($content);
        $sentence_count = preg_match_all("/[.!?]+/", $content);
        $avg_sentence_length =
            $sentence_count > 0 ? $word_count / $sentence_count : 0;

        // Count complex words (7+ characters)
        $words = preg_split("/\s+/", $content);
        $complex_words = 0;
        foreach ($words as $word) {
            $clean_word = preg_replace("/[^a-zA-Z]/", "", $word);
            if (strlen($clean_word) >= 7) {
                $complex_words++;
            }
        }
        $flesch_score =
            $word_count > 0
                ? 206.835 -
                    1.015 * ($word_count / max(1, $sentence_count)) -
                    84.6 * ($complex_words / $word_count)
                : 0;
        $readability =
            $flesch_score >= 60
                ? "good"
                : ($flesch_score >= 40
                    ? "ok"
                    : "complex");

        if ($readability === "good") {
            $geo["checks"][] = [
                "name" => "Clarity",
                "status" => "good",
                "message" => sprintf(
                    "Excellent readability (Flesch: %.0f)",
                    $flesch_score,
                ),
                "score" => 20,
            ];
            $total_score += 20;
        } elseif ($readability === "ok") {
            $geo["checks"][] = [
                "name" => "Clarity",
                "status" => "ok",
                "message" => sprintf(
                    "Average readability (Flesch: %.0f)",
                    $flesch_score,
                ),
                "score" => 12,
            ];
            $total_score += 12;
        } else {
            $geo["checks"][] = [
                "name" => "Clarity",
                "status" => "warning",
                "message" => sprintf(
                    "Complex text (Flesch: %.0f). Consider shorter sentences.",
                    $flesch_score,
                ),
                "score" => 5,
            ];
            $total_score += 5;
            $geo["suggestions"][] =
                "Break long sentences into shorter ones. Aim for 15-20 words per sentence average.";
        }

        // Check 5: Completeness - Does the content cover the topic thoroughly?
        $total_checks++;
        $focus_keyword = $post_config["seo_focus_keyword"] ?? "";

        if (!empty($focus_keyword)) {
            $keyword_in_intro =
                stripos(substr($content, 0, 200), $focus_keyword) !== false;
            $keyword_in_conclusion =
                stripos(substr($content, -200), $focus_keyword) !== false;
            $keyword_count = substr_count(
                strtolower($content),
                strtolower($focus_keyword),
            );
            $keyword_density =
                $word_count > 0 ? ($keyword_count / $word_count) * 100 : 0;

            if (
                $keyword_in_intro &&
                $keyword_in_conclusion &&
                $keyword_density >= 0.5
            ) {
                $geo["checks"][] = [
                    "name" => "Completeness",
                    "status" => "good",
                    "message" =>
                        "Topic covered comprehensively with keyword in intro and conclusion",
                    "score" => 20,
                ];
                $total_score += 20;
            } elseif ($keyword_density >= 0.5) {
                $geo["checks"][] = [
                    "name" => "Completeness",
                    "status" => "ok",
                    "message" => "Topic covered but improve keyword placement",
                    "score" => 12,
                ];
                $total_score += 12;
            } else {
                $geo["checks"][] = [
                    "name" => "Completeness",
                    "status" => "warning",
                    "message" =>
                        "Topic may not be fully covered. Ensure keyword appears in intro, body, and conclusion.",
                    "score" => 5,
                ];
                $total_score += 5;
                $geo["suggestions"][] =
                    "Include focus keyword in your introduction and conclusion paragraph";
            }
        } else {
            $geo["checks"][] = [
                "name" => "Completeness",
                "status" => "ok",
                "message" =>
                    "Focus keyword not set - cannot fully assess completeness",
                "score" => 10,
            ];
            $total_score += 10;
            $geo["suggestions"][] =
                "Set a focus keyword to enable full GEO analysis";
        }

        // Calculate final score
        $geo["score"] = $total_score;

        // Determine rating
        if ($geo["score"] >= 80) {
            $geo["rating"] = "excellent";
        } elseif ($geo["score"] >= 60) {
            $geo["rating"] = "good";
        } elseif ($geo["score"] >= 40) {
            $geo["rating"] = "fair";
        } else {
            $geo["rating"] = "poor";
        }

        // Add AI Overview eligibility note
        $geo["ai_overview_eligible"] = $geo["score"] >= 80;

        return new WP_REST_Response($geo, 200);
    }
}
