<?php
/**
 * REST API endpoint for the Sandbox
 *
 * POST /wp-json/slidemind/v2/sandbox/test
 * POST /wp-json/slidemind/v2/sandbox/render
 *
 * @package SlideMind
 * @since 2.0.0
 */

namespace SlideMind\API;

use SlideMind\Core\LLMProxy;
use SlideMind\Core\PromptEngine;
use SlideMind\Core\ApiKeyManager;
use SlideMind\Admin\SandboxController;

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

class SandboxEndpoint {

    /**
     * API namespace
     * @var string
     */
    private $namespace = 'slidemind/v2';

    /**
     * LLM proxy
     * @var LLMProxy
     */
    private $llm_proxy;

    /**
     * Prompt engine
     * @var PromptEngine
     */
    private $prompt_engine;

    /**
     * API key manager
     * @var ApiKeyManager
     */
    private $api_key_manager;

    /**
     * Sandbox controller
     * @var SandboxController
     */
    private $sandbox_controller;

    /**
     * Constructor
     *
     * @param LLMProxy $llm_proxy
     * @param PromptEngine $prompt_engine
     * @param ApiKeyManager $api_key_manager
     * @param SandboxController $sandbox_controller
     */
    public function __construct(
        LLMProxy $llm_proxy,
        PromptEngine $prompt_engine,
        ApiKeyManager $api_key_manager,
        SandboxController $sandbox_controller
    ) {
        $this->llm_proxy = $llm_proxy;
        $this->prompt_engine = $prompt_engine;
        $this->api_key_manager = $api_key_manager;
        $this->sandbox_controller = $sandbox_controller;
    }

    /**
     * Register REST routes
     */
    public function register_routes() {
        // Sandbox test endpoint (manual mode)
        register_rest_route($this->namespace, '/sandbox/test', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_sandbox_test'],
            'permission_callback' => [$this, 'check_permission'],
            'args'                => $this->get_test_args(),
        ]);

        // Prompt rendering endpoint
        register_rest_route($this->namespace, '/sandbox/render', [
            'methods'             => 'POST',
            'callback'            => [$this, 'handle_render_prompt'],
            'permission_callback' => [$this, 'check_permission'],
            'args'                => [
                'prompt' => [
                    'required'    => true,
                    'type'        => 'string',
                    'description' => 'Prompt with {{var}} variables',
                ],
                'variables' => [
                    'required'    => false,
                    'type'        => 'object',
                    'default'     => [],
                    'description' => 'Variables to inject',
                ],
            ],
        ]);
    }

    /**
     * Check permissions
     *
     * @return bool
     */
    public function check_permission() {
        return current_user_can('manage_slidemind_configs');
    }

    /**
     * Define test endpoint arguments
     *
     * @return array
     */
    private function get_test_args() {
        return [
            'model' => [
                'required'          => true,
                'type'              => 'string',
                'description'       => 'OpenRouter model ID',
                'sanitize_callback' => 'sanitize_text_field',
            ],
            'system_prompt' => [
                'required'          => true,
                'type'              => 'string',
                'description'       => 'System prompt with {{var}} variables',
            ],
            'temperature' => [
                'required' => false,
                'type'     => 'number',
                'default'  => 0.7,
                'minimum'  => 0,
                'maximum'  => 2,
            ],
            'max_tokens' => [
                'required' => false,
                'type'     => 'integer',
                'default'  => 1024,
                'minimum'  => 1,
                'maximum'  => 128000,
            ],
            'messages' => [
                'required'          => true,
                'type'              => 'array',
                'validate_callback' => [$this, 'validate_messages'],
                'description'       => 'Message history',
            ],
            'variables' => [
                'required'    => false,
                'type'        => 'object',
                'default'     => [],
                'description' => 'Variables to inject into the prompt',
            ],
            'session_id' => [
                'required'          => false,
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'description'       => 'Session ID for persistence',
            ],
            'output_variables' => [
                'required'    => false,
                'type'        => 'array',
                'default'     => [],
                'description' => 'Output variables for structured JSON response',
            ],
            'response_example' => [
                'required'    => false,
                'type'        => 'string',
                'default'     => '',
                'description' => 'Expected response format example',
            ],
            'provider' => [
                'required'          => false,
                'type'              => 'string',
                'default'           => '',
                'sanitize_callback' => 'sanitize_text_field',
                'description'       => 'LLM provider slug (openrouter, openai, anthropic, mistral)',
            ],
            'widget_mode' => [
                'required'          => false,
                'type'              => 'string',
                'default'           => 'qa',
                'sanitize_callback' => 'sanitize_text_field',
                'description'       => 'Widget mode (qa or chat) — drives strip_markdown setting selection',
            ],
        ];
    }

    /**
     * Validate message format
     *
     * @param array $messages
     * @return bool|\WP_Error
     */
    public function validate_messages($messages) {
        if (!is_array($messages) || empty($messages)) {
            return new \WP_Error(
                'invalid_messages',
                __('The messages parameter must be a non-empty array', 'slidemind'),
                ['status' => 400]
            );
        }

        foreach ($messages as $index => $message) {
            if (!isset($message['role']) || !isset($message['content'])) {
                return new \WP_Error(
                    'invalid_message_format',
                    /* translators: %d: message index in the array */
                    sprintf(__('The message at index %d must contain \'role\' and \'content\'', 'slidemind'), $index),
                    ['status' => 400]
                );
            }

            if (!in_array($message['role'], ['user', 'assistant'], true)) {
                return new \WP_Error(
                    'invalid_role',
                    /* translators: %s: the invalid role value */
                    sprintf(__('The role \'%s\' is not valid. Use \'user\' or \'assistant\'', 'slidemind'), $message['role']),
                    ['status' => 400]
                );
            }
        }

        return true;
    }

    /**
     * Handle sandbox test request
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response|\WP_Error
     */
    public function handle_sandbox_test($request) {
        // Parameters
        $model_id = $request->get_param('model');
        $system_prompt = $request->get_param('system_prompt');
        $temperature = $request->get_param('temperature') ?? 0.7;
        $max_tokens = $request->get_param('max_tokens') ?? 1024;
        $messages = $request->get_param('messages');
        $variables = $request->get_param('variables') ?? [];
        $session_id = $request->get_param('session_id');
        $output_variables = $request->get_param('output_variables') ?? [];
        $response_example = $request->get_param('response_example') ?? '';
        $provider = $request->get_param('provider');
        $widget_mode = $request->get_param('widget_mode') ?? 'qa';

        // Resolve provider (fallback to global)
        $valid_providers = LLMProxy::get_provider_slugs();
        if (empty($provider) || !in_array($provider, $valid_providers, true)) {
            $provider = get_option('slidemind_global_provider', 'openrouter');
        }

        // Retrieve the API key for the provider
        $api_key = $this->api_key_manager->get_global_api_key($provider);

        if (empty($api_key)) {
            return new \WP_Error(
                'no_api_key',
                /* translators: %s: provider name */
                sprintf(__('No API key configured for %s. Please configure a key in the settings.', 'slidemind'), $provider),
                ['status' => 400]
            );
        }

        // Build virtual configuration (simulates a saved config)
        $virtual_config = [
            'id'               => 0, // Indicates sandbox mode
            'model_id'         => $model_id,
            'system_prompt'    => $system_prompt,
            'temperature'      => $temperature,
            'max_tokens'       => $max_tokens,
            'api_key'          => $api_key,
            'provider'         => $provider,
            'output_variables' => $output_variables,
            'response_example' => $response_example,
            'course_response_example' => $variables['course_response_example'] ?? '',
            'module_response_example' => $variables['module_response_example'] ?? '',
        ];

        // Render the prompt for debug
        $rendered_info = $this->sandbox_controller->render_prompt($system_prompt, $variables);

        // Preventive markdown strip: instruct LLM to avoid markdown (mirror chat-endpoint behavior)
        $settings = get_option('slidemind_settings', []);
        $strip_active = ($widget_mode === 'chat')
            ? !empty($settings['strip_markdown_chat'])
            : !empty($settings['strip_markdown_qa']);

        if ($strip_active) {
            $virtual_config['system_prompt'] .= "\n\n--- FORMATTING INSTRUCTION ---\n"
                . 'IMPORTANT: Do NOT use any markdown formatting in your response. '
                . 'No bold (**), no italic (*), no headings (#), no bullet points (- or *), '
                . 'no code blocks (```), no links ([]()), no blockquotes (>). '
                . 'Write in plain text only, using natural sentence structure.';
        }

        // Call the LLM proxy
        $result = $this->llm_proxy->chat($virtual_config, $messages, $variables);

        if (!$result['success']) {
            return new \WP_Error(
                'llm_error',
                $result['error'],
                ['status' => 502]
            );
        }

        // Curative markdown strip: remove markdown from LLM response
        if ($strip_active) {
            if (isset($result['data']['message']['content'])) {
                $result['data']['message']['content'] = $this->strip_markdown($result['data']['message']['content']);
            }

            if (!empty($result['data']['structured_data'])) {
                foreach ($output_variables as $var) {
                    $var_name = $var['name'] ?? '';
                    $var_type = $var['type'] ?? 'texte';
                    if ($var_type === 'texte' && isset($result['data']['structured_data'][$var_name])) {
                        $result['data']['structured_data'][$var_name] = $this->strip_markdown(
                            $result['data']['structured_data'][$var_name]
                        );
                    }
                }
            }
        }

        // Save session if an ID is provided
        if (!empty($session_id)) {
            $history = $this->sandbox_controller->get_conversation_history($session_id);
            // Add the last user message
            $last_user_msg = end($messages);
            if ($last_user_msg) {
                $history[] = $last_user_msg;
            }
            // Add the assistant response
            $history[] = $result['data']['message'];
            $this->sandbox_controller->save_conversation_history($session_id, $history);
        }

        // Build response with debug info
        $response_data = [
            'success' => true,
            'message' => $result['data']['message'],
            'usage'   => $result['data']['usage'],
            'meta'    => [
                'model'         => $result['data']['model'],
                'response_time' => $result['data']['response_time'],
            ],
            'debug'   => [
                'prompt_original'   => $rendered_info['original'],
                'prompt_rendered'   => $rendered_info['rendered'],
                'variables_found'   => $rendered_info['variables_found'],
                'variables_used'    => $rendered_info['variables_used'],
                'variables_missing' => $rendered_info['variables_missing'],
            ],
        ];

        // Forward structured data if output_variables produced it
        if (isset($result['data']['structured_data'])) {
            $response_data['structured'] = !empty($result['data']['structured']);
            $response_data['structured_data'] = $result['data']['structured_data'];
        }

        $response = new \WP_REST_Response($response_data, 200);

        // Anti-cache headers
        $response->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
        $response->header('Pragma', 'no-cache');

        return $response;
    }

    /**
     * Strips markdown formatting from text. Mirrors ChatEndpoint::strip_markdown
     * to keep sandbox output consistent with the production widget.
     *
     * @param string $text
     * @return string
     */
    private function strip_markdown(string $text): string {
        $text = preg_replace('/```[a-z]*\n([\s\S]*?)\n?```/m', '$1', $text) ?? $text;
        $text = preg_replace('/```[a-z]*\n?/m', '', $text) ?? $text;
        $text = preg_replace('/`([^`]+)`/', '$1', $text) ?? $text;
        $text = preg_replace('/!\[([^\]]*)\]\([^)]+\)/', '$1', $text) ?? $text;
        $text = preg_replace('/\[([^\]]+)\]\([^)]+\)/', '$1', $text) ?? $text;
        $text = preg_replace('/^[-*_]{3,}\s*$/m', '', $text) ?? $text;
        $text = preg_replace('/\*{3}(.+?)\*{3}/', '$1', $text) ?? $text;
        $text = preg_replace('/_{3}(.+?)_{3}/', '$1', $text) ?? $text;
        $text = preg_replace('/\*{2}(.+?)\*{2}/', '$1', $text) ?? $text;
        $text = preg_replace('/_{2}(.+?)_{2}/', '$1', $text) ?? $text;
        $text = preg_replace('/(?<!\*)\*(?!\s)(.+?)(?<!\s)\*(?!\*)/', '$1', $text) ?? $text;
        $text = preg_replace('/(?<!\w)_(?!\s)(.+?)(?<!\s)_(?!\w)/', '$1', $text) ?? $text;
        $text = preg_replace('/~~(.+?)~~/', '$1', $text) ?? $text;
        $text = preg_replace('/^#{1,6}\s+/m', '', $text) ?? $text;
        $text = preg_replace('/^>\s?/m', '', $text) ?? $text;
        $text = preg_replace('/^[\t ]*[-*+]\s+/m', '', $text) ?? $text;
        $text = preg_replace('/^[\t ]*\d+\.\s+/m', '', $text) ?? $text;
        $text = preg_replace('/\n{3,}/', "\n\n", $text) ?? $text;
        return trim($text);
    }

    /**
     * Handle prompt rendering request
     *
     * @param \WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function handle_render_prompt($request) {
        $prompt = $request->get_param('prompt');
        $variables = $request->get_param('variables') ?? [];

        $result = $this->sandbox_controller->render_prompt($prompt, $variables);

        return new \WP_REST_Response([
            'success'           => true,
            'original'          => $result['original'],
            'rendered'          => $result['rendered'],
            'variables_found'   => $result['variables_found'],
            'variables_used'    => $result['variables_used'],
            'variables_missing' => $result['variables_missing'],
        ], 200);
    }
}
