<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * ============================================================================
 *  CENTRAL AI PROVIDER ROUTER
 * ============================================================================
 *
 *  This class is the SINGLE point for deciding:
 *   - Which AI provider to use: OpenAI, Google Gemini, or future providers.
 *   - Which provider-specific class should handle the request.
 *
 *  AJAX handlers and UI/frontend NEVER talk directly to providers.
 *  They ALWAYS call this router → routing stays consistent forever.
 *
 *  BENEFITS:
 *    ✔ OpenAI code stays clean and untouched
 *    ✔ Gemini implementation stays isolated
 *    ✔ Adding new providers becomes extremely easy
 *    ✔ JS never changes (normalized output structure)
 *
 *  Every method below delegates work to the correct provider.
 *  All provider classes MUST return normalized output arrays.
 */
class SftcyWordaiAiProviderRouter {

    private static function fail_response( $message, $provider = 'none' ) {
        return [
            'provider'    => $provider,
            'status'      => 'fail',
            'feedbackMsg' => $message,
        ];
    }

    private static function log_failure( $subsystem, $event_code, $message, $provider = '', $context = array(), $object_type = '', $object_id = 0 ) {
        if ( class_exists( 'SftcyWordaiSupport' ) ) {
            SftcyWordaiSupport::log_event(
                $subsystem,
                'error',
                $event_code,
                $message,
                $context,
                $provider,
                $object_type,
                $object_id
            );
        }
    }

    private static function log_provider_response( $subsystem, $provider, $response, $context = array() ) {
        if ( is_wp_error( $response ) ) {
            self::log_failure(
                $subsystem,
                $subsystem . '_wp_error',
                $response->get_error_message(),
                $provider,
                $context
            );
            return;
        }

        if ( is_array( $response ) && ( $response['status'] ?? '' ) === 'fail' ) {
            self::log_failure(
                $subsystem,
                $subsystem . '_failed',
                (string) ( $response['feedbackMsg'] ?? $response['errorMessage'] ?? $response['reply'] ?? __( 'Provider request failed.', 'wordai-pro' ) ),
                $provider,
                $context
            );
        }
    }


    /**
     * ======================================================================
     * Build provider-aware content params.
     *
     * OpenAI → set_openai_params() + messages[]
     * {
     *   "messages": [
     *     { "role": "user", "content": "your prompt here" }
     *   ]
     * }
     *
     * Gemini → set_gemini_params()  + body
     *
     * {
     *   "contents": [
     *       {
     *          "role": "user",
     *          "parts": [
     *               { "text": "your prompt here" }
     *           ]
     *     } 
     *   ]
     *  }
     *
     * 
     * This guarantees that each provider always receives the correct structure.
     * ======================================================================
     */
    public static function build_content_params($prompt) {

        $provider = self::get_active_provider();

        if ( ! SftcyWordaiBase::sc_wordai_provider_supports( 'content', $provider ) ) {
            $response = self::fail_response(
                sprintf(
                    __( '%s does not support content generation in WordAI.', 'wordai-pro' ),
                    SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
                ),
                $provider
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'build_content_params' ) );
            return $response;
        }

        /*--------------------------------------------------------------
        * GOOGLE GEMINI
        *--------------------------------------------------------------*/
        if ($provider === 'google' && class_exists('SftcyWordaiGoogleGeminiApi')) {

            $gem = SftcyWordaiGoogleGeminiApi::set_gemini_params($prompt);            

            return [
                'provider' => 'google',
                'params'   => [
                    'model' => $gem['model'],
                    'body'  => $gem['body'],
                ],
                // Keep Gemini content on the stable JSON response path. Its streaming
                // chunk format can arrive without SSE data prefixes and caused partial
                // long-form content in the modal.
                'stream'   => false,
            ];
        }

        /*--------------------------------------------------------------
        * ANTHROPIC CLAUDE
        *--------------------------------------------------------------*/
        if ($provider === 'anthropic' && class_exists('SftcyWordaiAnthropicApi')) {

            $claude = SftcyWordaiAnthropicApi::set_anthropic_params($prompt);

            return [
                'provider' => 'anthropic',
                'params'   => [
                    'model' => $claude['model'],
                    'body'  => $claude['body'],
                ],
                // Keep editor modal content generation on the normalized JSON path.
                // Multiple modal items can run together, and raw Anthropic streaming
                // responses are more fragile there than the standard response path.
                'stream'   => false,
            ];
        }

        /*--------------------------------------------------------------
        * xAI GROK
        *--------------------------------------------------------------*/
        if ($provider === 'xai' && class_exists('SftcyWordaiXaiApi')) {
            return [
                'provider' => 'xai',
                'params'   => SftcyWordaiXaiApi::set_xai_params($prompt),
                'stream'   => false,
            ];
        }

        /*--------------------------------------------------------------
        * OPENAI
        *--------------------------------------------------------------*/
        if ($provider === 'openai' && class_exists('SftcyWordaiOpenai')) {

            $p = SftcyWordaiOpenai::set_openai_params();

            // Add the prompt to messages[]
            $p['messages'] = [
                [
                    'role'    => 'user',
                    'content' => $prompt,
                ]
            ];

            return [
                'provider' => 'openai',
                'params'   => $p,
                'stream'   => isset($p['stream']) ? (bool) $p['stream'] : false,
            ];
        }

        $response = self::fail_response(
            sprintf(
                __( 'Provider class is not available for %s content generation.', 'wordai-pro' ),
                SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
            ),
            $provider
        );
        self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'build_content_params' ) );
        return $response;
    }


    /**
     * ============================================================================
     * Build Image Params (OpenAI + Gemini)
     * ============================================================================
     */
    public static function build_image_params( $prompt ) {

        $provider = self::get_active_provider();

        if ( ! SftcyWordaiBase::sc_wordai_provider_supports( 'image', $provider ) ) {
            if ( $provider === 'anthropic' ) {
                $response = self::fail_response(
                    __( 'Anthropic Claude does not currently support native image generation from a Claude API key. Use OpenAI, Google Gemini, or xAI Grok to generate images in WordAI.', 'wordai-pro' ),
                    $provider
                );
                self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'build_image_params' ) );
                return $response;
            }

            $response = self::fail_response(
                sprintf(
                    __( '%s does not support image generation in WordAI.', 'wordai-pro' ),
                    SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
                ),
                $provider
            );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'build_image_params' ) );
            return $response;
        }

        /*--------------------------------------------------------------
        * GOOGLE GEMINI IMAGES
        * - expects SftcyWordaiGoogleGeminiApi::set_gemini_image_params()
        *   to return: [ 'model' => 'gemini-image-model', 'body' => [ ... ] ]
        *--------------------------------------------------------------*/
        // if ( $provider === 'google' && class_exists( 'SftcyWordaiGoogleGeminiApi' ) ) {

        //     $img = SftcyWordaiGoogleGeminiApi::set_gemini_image_params( $prompt );

        //     return [
        //         'provider' => 'google',
        //         'params'   => [
        //             'model' => $img['model'],
        //             'body'  => $img['body'],
        //         ],
        //     ];
        // }

        if ( $provider === 'google' && class_exists( 'SftcyWordaiGoogleGeminiApi' ) ) {

            $img = SftcyWordaiGoogleGeminiApi::set_gemini_image_params( $prompt );

            return [
                'provider' => 'google',
                'params'   => [
                    'model' => $img['model'],
                    'body'  => $img['body'],
                    'mime'  => $img['mime'] ?? null,
                ],
            ];
        }

        /* xAI Grok Images */
        if ( $provider === 'xai' && class_exists( 'SftcyWordaiXaiApi' ) ) {
            return [
                'provider' => 'xai',
                'params'   => SftcyWordaiXaiApi::set_xai_image_params( $prompt ),
            ];
        }

        /*--------------------------------------------------------------
        * OPENAI IMAGES (existing)
        * - reuses your current image params builder
        *--------------------------------------------------------------*/
        if ( $provider === 'openai' && class_exists( 'SftcyWordaiOpenai' ) ) {

            $api = SftcyWordaiOpenai::set_openai_image_params();
            $api['prompt'] = $prompt;

            return [
                'provider' => 'openai',
                'params'   => $api,
            ];
        }

        // No provider
        $response = self::fail_response(
            sprintf(
                __( 'Provider class is not available for %s image generation.', 'wordai-pro' ),
                SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
            ),
            $provider
        );
        self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'build_image_params' ) );
        return $response;
    }




    /**
     * Return active AI provider slug.
     *
     * Possible return:
     *   'openai'
     *   'google'
     *   'anthropic' (future)
     *   'mistral'   (future)
     *
     * @return string
     */
    public static function get_active_provider() {
        return SftcyWordaiBase::sc_wordai_get_current_ai_provider();
    }

    /*============================================================================
     *  CONTENT GENERATION (Chat / Completion)
     *============================================================================*/

    /**
     * Generate content using the active provider.
     *
     * - Accepts unified $args array
     * - Delegates to provider-specific class
     * - MUST return normalized output structure
     *
     * @param array $args
     * @return array|WP_Error
     */
    public static function generate_content( $args = array() ) {

        if ( isset( $args['status'] ) && $args['status'] === 'fail' ) {
            return $args;
        }

        $provider = sanitize_key( (string) ( $args['provider'] ?? self::get_active_provider() ) );

        /**
         * We expect $args = [
         *     'provider' => 'openai' | 'google',
         *     'params'   => [...],      <-- this must be the real API params
         *     'stream'   => true|false
         * ]
         */
        $api_params = $args['params'] ?? [];
        $stream     = $args['stream'] ?? false;

        if ( ! SftcyWordaiBase::sc_wordai_is_valid_provider( $provider ) ) {
            $response = self::fail_response( __( 'No valid AI provider available for content generation.', 'wordai-pro' ) );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content' ) );
            return $response;
        }

        if ( ! SftcyWordaiBase::sc_wordai_provider_supports( 'content', $provider ) ) {
            $response = self::fail_response(
                sprintf(
                    __( '%s does not support content generation in WordAI.', 'wordai-pro' ),
                    SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
                ),
                $provider
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content' ) );
            return $response;
        }

        /*----------------------------------------------------------
        * GOOGLE GEMINI
        *----------------------------------------------------------*/
        if ( $provider === 'google' && class_exists( 'SftcyWordaiGoogleGeminiApi' ) ) {
            $response = SftcyWordaiGoogleGeminiApi::create_content(
                $api_params,   // send ONLY valid Gemini params
                $stream
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content', 'stream' => (bool) $stream ) );
            return $response;
        }

        /*----------------------------------------------------------
        * ANTHROPIC CLAUDE
        *----------------------------------------------------------*/
        if ( $provider === 'anthropic' && class_exists( 'SftcyWordaiAnthropicApi' ) ) {
            $response = SftcyWordaiAnthropicApi::create_content(
                $api_params,
                $stream
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content', 'stream' => (bool) $stream ) );
            return $response;
        }

        /*----------------------------------------------------------
        * xAI GROK
        *----------------------------------------------------------*/
        if ( $provider === 'xai' && class_exists( 'SftcyWordaiXaiApi' ) ) {
            $response = SftcyWordaiXaiApi::create_content(
                $api_params,
                $stream
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content', 'stream' => (bool) $stream ) );
            return $response;
        }

        /*----------------------------------------------------------
        * OPENAI
        *----------------------------------------------------------*/
        if ( $provider === 'openai' && class_exists( 'SftcyWordaiOpenai' ) ) {
            $response = SftcyWordaiOpenai::create_content(
                $api_params    // send ONLY valid OpenAI params
            );
            self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content', 'stream' => (bool) $stream ) );
            return $response;
        }

        $response = self::fail_response(
            sprintf(
                __( 'Provider class is not available for %s content generation.', 'wordai-pro' ),
                SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
            ),
            $provider
        );
        self::log_provider_response( 'content', $provider, $response, array( 'stage' => 'generate_content' ) );
        return $response;
    }

    /*============================================================================
    *  IMAGE GENERATION -  Router Provider
    *============================================================================*/
    /**
     * Generate images using active provider.
     *
     * @param array $args
     *   Either:
     *     - Output of build_image_params(): ['provider' => 'google|openai', 'params' => [ ... ]]
     *     - Or direct params array for backward compatibility.
     *
     * @return array|WP_Error
     */
    public static function generate_image( $args = array() ) {

        if ( isset( $args['status'] ) && $args['status'] === 'fail' ) {
            return $args;
        }

        // Default: use active provider
        $provider = self::get_active_provider();
        $params   = $args;

        // If called with build_image_params() structure, normalize it
        if ( isset( $args['provider'], $args['params'] ) ) {
            $provider = $args['provider'];
            $params   = $args['params'];
        }

        $provider = sanitize_key( (string) $provider );

        if ( ! SftcyWordaiBase::sc_wordai_is_valid_provider( $provider ) ) {
            $response = new WP_Error(
                'wordai_invalid_provider',
                __( 'No valid AI provider for image generation.', 'wordai-pro' )
            );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
            return $response;
        }

        if ( ! SftcyWordaiBase::sc_wordai_provider_supports( 'image', $provider ) ) {
            if ( $provider === 'anthropic' ) {
                $response = new WP_Error(
                    'wordai_unsupported_image_provider',
                    __( 'Anthropic Claude does not currently support native image generation from a Claude API key. Use OpenAI, Google Gemini, or xAI Grok to generate images in WordAI.', 'wordai-pro' )
                );
                self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
                return $response;
            }

            $response = new WP_Error(
                'wordai_unsupported_image_provider',
                sprintf(
                    __( '%s does not support image generation in WordAI.', 'wordai-pro' ),
                    SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
                )
            );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
            return $response;
        }

        /* Google Gemini */
        if ( $provider === 'google' && class_exists( 'SftcyWordaiGoogleGeminiApi' ) ) {
            $response = SftcyWordaiGoogleGeminiApi::generate_image( $params );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
            return $response;
        }

        /* xAI Grok */
        if ( $provider === 'xai' && class_exists( 'SftcyWordaiXaiApi' ) ) {
            $response = SftcyWordaiXaiApi::generate_image( $params );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
            return $response;
        }

        /* OpenAI */
        if ( $provider === 'openai' && class_exists( 'SftcyWordaiOpenai' ) ) {
            $response = SftcyWordaiOpenai::generate_image( $params );
            self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
            return $response;
        }

        $response = new WP_Error(
            'wordai_provider_class_missing',
            sprintf(
                __( 'Provider class is not available for %s image generation.', 'wordai-pro' ),
                SftcyWordaiBase::sc_wordai_get_provider_label( $provider )
            )
        );
        self::log_provider_response( 'image', $provider, $response, array( 'stage' => 'generate_image' ) );
        return $response;
    }


    /*============================================================================
     *  EMBEDDINGS (Agent Indexing System)
     *============================================================================*/

    /**
     * Resolve correct embedding agent class dynamically.
     *
     * @return string|null
     */
    public static function get_embedding_agent_class() {
        $class = SftcyWordaiBase::sc_wordai_get_embedding_agent_class();

        if ( $class && class_exists( $class ) ) {
            return $class;
        }

        return null;
    }

    /**
     * Create embeddings for an array of texts.
     *
     * @param array  $texts
     * @param string $model
     *
     * @return array
     */
    public static function create_embeddings( $texts = array(), $model = '' ) {

        $agent = self::get_embedding_agent_class();

        if ( ! $agent || ! class_exists( $agent ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => __( 'No embedding agent available for active provider.', 'wordai-pro' ),
            ];
        }

        if ( ! method_exists( $agent, 'create_embeddings' ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => sprintf(
                    __( 'Embedding agent "%s" does not implement create_embeddings().', 'wordai-pro' ),
                    $agent
                ),
            ];
        }

        return call_user_func( [ $agent, 'create_embeddings' ], (array) $texts, $model );
    }

    /**
     * Chunk text using provider's chunking logic.
     *
     * @param string $text
     * @param int    $chunk_size
     * @return array
     */
    public static function chunk_text( $text = '', $chunk_size = 500 ) {

        $agent = self::get_embedding_agent_class();

        if ( $agent && class_exists( $agent ) && method_exists( $agent, 'chunk_text' ) ) {
            return call_user_func( [ $agent, 'chunk_text' ], (string) $text, (int) $chunk_size );
        }

        // Fallback → OpenAI chunker
        if ( class_exists( 'SftcyWordaiAgentOpenai' ) && method_exists( 'SftcyWordaiAgentOpenai', 'chunk_text' ) ) {
            return SftcyWordaiAgentOpenai::chunk_text( $text, $chunk_size );
        }

        // Last fallback → return full text as 1 chunk
        return [ (string) $text ];
    }

    /**
     * Estimate token cost for embeddings.
     *
     * @param int    $total_words
     * @param string $model
     * @return array
     */
    public static function estimate_embedding_cost( $total_words = 0, $model = '' ) {

        $agent = self::get_embedding_agent_class();

        if ( ! $agent || ! class_exists( $agent ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => __( 'No embedding agent available for cost estimation.', 'wordai-pro' ),
            ];
        }

        if ( ! method_exists( $agent, 'estimate_cost' ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => sprintf(
                    __( 'Embedding agent "%s" does not implement estimate_cost().', 'wordai-pro' ),
                    $agent
                ),
            ];
        }

        return call_user_func( [ $agent, 'estimate_cost' ], (int) $total_words, $model );
    }

    /**
     * Store an embedding vector in DB.
     *
     * @param int    $source_id
     * @param string $chunk_text
     * @param array  $embedding
     * @param string $model
     * @return void
     */
    public static function store_embedding( $source_id, $chunk_text, $embedding, $model = '' ) {

        $agent = self::get_embedding_agent_class();

        if ( $agent && class_exists( $agent ) && method_exists( $agent, 'store_embedding' ) ) {
            call_user_func( 
                [ $agent, 'store_embedding' ],
                (int) $source_id,
                (string) $chunk_text,
                (array) $embedding,
                $model
            );
        }
    }
}
