<?php
/**
 * =====================================================================
 *  WordAI Agent — OpenAI Embedding API Handler (Multi-provider ready)
 *  -------------------------------------------------------------------
 * -  Parallel to SftcyWordaiAgentGemini
 *  - Handles all Embedding-related API calls for WordAI Agent (OpenAI)
 *  - Uses global API settings
 *  - Now stores provider + model + chunk_hash in embeddings table
 *  - Safe for co-existence with Gemini / other providers
 * =====================================================================
 *  @since 1.0.0
 */

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

class SftcyWordaiAgentOpenai {

    /** @var string|null $API_KEY */
    private static $API_KEY = null;

    /** @var string $EMBEDDING_ENDPOINT */
    private static $EMBEDDING_ENDPOINT = 'https://api.openai.com/v1/embeddings';

    /** @var string PROVIDER slug stored in DB (for embeddings.provider) */
    const PROVIDER = 'openai';

    /**
     * Default OpenAI embedding model.
     * - For example: 'text-embedding-3-small'
     */
    const DEFAULT_EMBEDDING_MODEL = 'text-embedding-3-small';    

    public static function embedding_models() {
        return [
            'text-embedding-3-small' => 'text-embedding-3-small',
            'text-embedding-3-large' => 'text-embedding-3-large',
        ];
    }

    public static function normalize_embedding_model( $model = '' ) {
        $model = trim( (string) $model );

        return isset( self::embedding_models()[ $model ] ) ? $model : self::DEFAULT_EMBEDDING_MODEL;
    }

    private static function ensure_api_key() {
        if ( self::$API_KEY !== null ) {
            return;
        }

        $settings = (array) maybe_unserialize( get_option( 'sftcy-wordai-openai-apisettings-data' ) );
        self::$API_KEY = isset( $settings['wordai-openai-api-key-data'] )
            ? trim( (string) $settings['wordai-openai-api-key-data'] )
            : '';
    }


    /**
     * ------------------------------------------------------------
     * Initialize API key from global WordAI settings
     * ------------------------------------------------------------
     */
    public function __construct() {
        self::ensure_api_key();
    }


    /**
     * ------------------------------------------------------------
     * Generate embeddings for given text chunks (OpenAI)
     * ------------------------------------------------------------
     *
     * @param array  $texts Array of text chunks
     * @param string $model 'text-embedding-3-small' | 'text-embedding-3-large' | ...
     *
     * @return array        Structured response with status + data
     * ------------------------------------------------------------
     */
    public static function create_embeddings( $texts = [], $model = self::DEFAULT_EMBEDDING_MODEL ) {

        self::ensure_api_key();
        $model = self::normalize_embedding_model( $model );

        if ( empty( $texts ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => __( 'No valid text provided for embedding.', 'wordai-pro' ),
            ];
        }

        if ( empty( self::$API_KEY ) ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => __( 'OpenAI API key is missing.', 'wordai-pro' ),
            ];
        }

        $vectors = [];
        foreach ( (array) $texts as $chunk ) {
            $response = wp_remote_post(
                self::$EMBEDDING_ENDPOINT,
                [
                    'headers'   => [
                        'Authorization' => 'Bearer ' . self::$API_KEY,
                        'Content-Type'  => 'application/json',
                    ],
                    'body'      => wp_json_encode(
                        [
                            'model' => $model,
                            'input' => (string) $chunk,
                        ]
                    ),
                    'timeout'   => 40,
                    'sslverify' => class_exists( 'SftcyWordaiBase' ) ? SftcyWordaiBase::sc_wordai_should_verify_ssl() : true,
                ]
            );

            if ( is_wp_error( $response ) ) {
                return [
                    'status'      => 'fail',
                    'feedbackMsg' => __( 'Embedding request failed: ', 'wordai-pro' ) . $response->get_error_message(),
                ];
            }

            $code = (int) wp_remote_retrieve_response_code( $response );
            $raw  = wp_remote_retrieve_body( $response );
            $json = json_decode( $raw, true );

            if ( $code !== 200 || empty( $json['data'][0]['embedding'] ) ) {
                return [
                    'status'      => 'fail',
                    'feedbackMsg' => __( 'Embedding error: ', 'wordai-pro' ) . ( $json['error']['message'] ?? 'Unknown error' ),
                ];
            }

            $vectors[] = $json['data'][0]['embedding'];
        }

        return [
            'status'      => 'success',
            'feedbackMsg' => 'Embeddings created successfully.',
            'embeddings'  => $vectors,
            'provider'    => self::PROVIDER,
            'model'       => $model,
        ];
    }


    /**
     * ------------------------------------------------------------
     * Split text into smaller chunks
     * ------------------------------------------------------------
     *
     * If you already had this method, you can keep it.
     *
     * @param string  $text
     * @param integer $chunk_size
     * @return array
     * ------------------------------------------------------------
     */
    public static function chunk_text( $text = '', $chunk_size = 500 ) {
        // Simple example: split by ~chunk_size words.
        // If you already had a more advanced logic, keep it.
        $text = trim( wp_strip_all_tags( $text ) );
        if ( $text === '' ) {
            return [];
        }

        $words  = preg_split( '/\s+/', $text );
        $chunks = [];
        $buffer = [];

        foreach ( $words as $word ) {
            $buffer[] = $word;
            if ( count( $buffer ) >= $chunk_size ) {
                $chunks[] = implode( ' ', $buffer );
                $buffer   = [];
            }
        }

        if ( ! empty( $buffer ) ) {
            $chunks[] = implode( ' ', $buffer );
        }

        return $chunks;
    }


    /**
     * ------------------------------------------------------------
     * Estimate cost for OpenAI embeddings
     * ------------------------------------------------------------
     *
     * Re-usable from backend (Ajax) to give users cost idea.
     * Uses OpenAI's current embedding pricing (approx).
     *
     * @param int    $total_words
     * @param string $model
     * @return array
     * ------------------------------------------------------------
     */
    public static function estimate_cost( $total_words = 0, $model = self::DEFAULT_EMBEDDING_MODEL ) {
        $model = self::normalize_embedding_model( $model );

        if ( $total_words <= 0 ) {
            return [
                'status'      => 'fail',
                'feedbackMsg' => __( 'No valid words provided for cost estimation.', 'wordai-pro' ),
            ];
        }

        // Rough word→token conversion (~0.75 words per token)
        $tokens = (int) ceil( $total_words / 0.75 );

        /**
         * OpenAI embedding pricing (example, adjust if needed):
         *  - text-embedding-3-small: $0.02 per 1M tokens
         *  - text-embedding-3-large: $0.13 per 1M tokens
         */
        switch ( $model ) {
            case 'text-embedding-3-large':
                $rate_per_million = 0.13;
                break;
            case 'text-embedding-3-small':
            default:
                $rate_per_million = 0.02;
                break;
        }

        $rate_per_token = $rate_per_million / 1_000_000;
        $cost           = round( $tokens * $rate_per_token, 6 );

        return [
            'status'         => 'success',
            'total_tokens'   => $tokens,
            'estimated_cost' => '$' . $cost,
            'model'          => $model,
            'provider'       => self::PROVIDER,
        ];
    }    

    /**
     * ------------------------------------------------------------
     * Helper: compute deterministic hash of a text chunk
     * ------------------------------------------------------------
     *
     * @param string $chunk_text
     * @return string
     * ------------------------------------------------------------
     */
    public static function compute_chunk_hash( $chunk_text ) {
        $chunk_text = (string) $chunk_text;
        return hash( 'sha256', $chunk_text );
    }    

    /**
         * ------------------------------------------------------------
         * Store Embedding Vector into DB (OpenAI)
         * ------------------------------------------------------------
         *
         * Mirrors SftcyWordaiAgentGemini::store_embedding() but with
         * provider = 'openai'.
         *
         * @param int    $source_id
         * @param string $chunk_text
         * @param array  $embedding
         * @param string $model
         * ------------------------------------------------------------
         */
        public static function store_embedding( $source_id, $chunk_text, $embedding, $model = self::DEFAULT_EMBEDDING_MODEL ) {
            global $wpdb;

            $table      = $wpdb->prefix . 'wordai_agent_embeddings';
            $provider   = self::PROVIDER;
            $chunk_hash = self::compute_chunk_hash( $chunk_text );

            // Avoid duplicates for this provider+model+chunk_hash
            $exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT id FROM {$table}
                    WHERE source_id  = %d
                    AND provider   = %s
                    AND model      = %s
                    AND chunk_hash = %s
                    LIMIT 1",
                    $source_id,
                    $provider,
                    $model,
                    $chunk_hash
                )
            );

            if ( $exists ) {
                return;
            }

            $wpdb->insert(
                $table,
                [
                    'source_id'  => intval( $source_id ),
                    'chunk_text' => maybe_serialize( $chunk_text ),
                    'embedding'  => maybe_serialize( $embedding ),
                    'model'      => $model,
                    'provider'   => $provider,
                    'chunk_hash' => $chunk_hash,
                    'created_at' => current_time( 'mysql' ),
                ],
                [ '%d', '%s', '%s', '%s', '%s', '%s', '%s' ]
            );
        }
    }
