<?php
/**
 * Codex Provider (OpenAI API)
 *
 * Direct integration with OpenAI's API for text generation
 *
 * @package WP_Agentic_Writer
 */

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

class WP_Agentic_Writer_Codex_Provider implements WP_Agentic_Writer_AI_Provider_Interface {

	/**
	 * OpenAI API key
	 *
	 * @var string
	 */
	private $api_key = '';

	/**
	 * API endpoint
	 *
	 * @var string
	 */
	private $api_endpoint = 'https://api.openai.com/v1/chat/completions';

	/**
	 * Default model
	 *
	 * @var string
	 */
	private $model = 'gpt-4o';

	/**
	 * Constructor
	 */
	public function __construct() {
		$settings = get_option( 'wp_agentic_writer_settings', array() );
		$this->api_key = $settings['codex_api_key'] ?? '';
		$this->model = $settings['codex_model'] ?? 'gpt-4o';
	}

	/**
	 * Non-streaming chat completion
	 *
	 * @param array  $messages Array of message objects.
	 * @param array  $options  Optional parameters.
	 * @param string $type     Task type.
	 * @return array|WP_Error Response with content, model, tokens, cost.
	 */
	public function chat( $messages, $options = array(), $type = 'planning' ) {
		if ( ! $this->is_configured() ) {
			return new WP_Error(
				'not_configured',
				__( 'Codex API key not configured.', 'wp-agentic-writer' )
			);
		}

		$model = $options['model'] ?? $this->model;
		$temperature = $options['temperature'] ?? 0.7;
		$max_tokens = $options['max_tokens'] ?? null;

		$body = array(
			'model' => $model,
			'messages' => $messages,
			'temperature' => $temperature,
		);

		if ( $max_tokens ) {
			$body['max_tokens'] = $max_tokens;
		}

		$start_time = microtime( true );

		$response = wp_remote_post(
			$this->api_endpoint,
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $this->api_key,
					'Content-Type' => 'application/json',
				),
				'body' => wp_json_encode( $body ),
				'timeout' => 120,
			)
		);

		$generation_time = microtime( true ) - $start_time;

		if ( is_wp_error( $response ) ) {
			return new WP_Error(
				'connection_failed',
				sprintf(
					/* translators: %s: error message */
					__( 'Codex connection failed: %s', 'wp-agentic-writer' ),
					$response->get_error_message()
				)
			);
		}

		$code = wp_remote_retrieve_response_code( $response );
		if ( 200 !== $code ) {
			$body_response = wp_remote_retrieve_body( $response );
			$error_data = json_decode( $body_response, true );
			return new WP_Error(
				'api_error',
				sprintf(
					/* translators: %1$d: HTTP status code, %2$s: error message */
					__( 'Codex error (%1$d): %2$s', 'wp-agentic-writer' ),
					$code,
					$error_data['error']['message'] ?? $body_response
				)
			);
		}

		$response_body = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( ! isset( $response_body['choices'][0]['message']['content'] ) ) {
			return new WP_Error(
				'invalid_response',
				__( 'Invalid response format from Codex', 'wp-agentic-writer' )
			);
		}

		$content = $response_body['choices'][0]['message']['content'];
		$usage = $response_body['usage'] ?? array();

		// Calculate cost based on OpenAI pricing
		$cost = $this->calculate_cost( $model, $usage );

		return array(
			'content' => $content,
			'model' => $model,
			'input_tokens' => $usage['prompt_tokens'] ?? 0,
			'output_tokens' => $usage['completion_tokens'] ?? 0,
			'total_tokens' => $usage['total_tokens'] ?? 0,
			'cost' => $cost,
			'generation_time' => $generation_time,
		);
	}

	/**
	 * Streaming chat completion
	 *
	 * @param array    $messages Array of message objects.
	 * @param array    $options  Optional parameters.
	 * @param string   $type     Task type.
	 * @param callable $callback Function to call with each chunk.
	 * @return array|WP_Error Response or error.
	 */
	public function chat_stream( $messages, $options = array(), $type = 'planning', $callback = null ) {
		if ( ! $this->is_configured() ) {
			return new WP_Error(
				'not_configured',
				__( 'Codex API key not configured.', 'wp-agentic-writer' )
			);
		}

		$model = $options['model'] ?? $this->model;
		$temperature = $options['temperature'] ?? 0.7;

		$body = array(
			'model' => $model,
			'messages' => $messages,
			'temperature' => $temperature,
			'stream' => true,
		);

		if ( isset( $options['max_tokens'] ) ) {
			$body['max_tokens'] = $options['max_tokens'];
		}

		$accumulated_content = '';
		$accumulated_usage = array();
		$buffer = '';

		$accumulating_callback = function( $chunk, $is_complete ) use ( &$accumulated_content, $callback ) {
			if ( ! $is_complete && ! empty( $chunk ) ) {
				$accumulated_content .= $chunk;
			}

			if ( $callback ) {
				call_user_func( $callback, $chunk, $is_complete, $accumulated_content );
			}
		};

		$ch = curl_init( $this->api_endpoint );

		curl_setopt_array( $ch, array(
			CURLOPT_POST => true,
			CURLOPT_RETURNTRANSFER => false,
			CURLOPT_WRITEFUNCTION => function( $curl, $data ) use ( &$buffer, $accumulating_callback, &$accumulated_usage ) {
				$buffer .= $data;

				while ( true ) {
					$newline_pos = strpos( $buffer, "\n" );
					if ( false === $newline_pos ) {
						break;
					}

					$line = substr( $buffer, 0, $newline_pos );
					$buffer = substr( $buffer, $newline_pos + 1 );

					$line = trim( $line );
					if ( empty( $line ) || 0 !== strpos( $line, 'data: ' ) ) {
						continue;
					}

					$json_str = substr( $line, 6 );

					if ( '[DONE]' === $json_str ) {
						call_user_func( $accumulating_callback, '', true );
						return strlen( $data );
					}

					$chunk = json_decode( $json_str, true );
					if ( isset( $chunk['choices'][0]['delta']['content'] ) ) {
						$content = $chunk['choices'][0]['delta']['content'];
						call_user_func( $accumulating_callback, $content, false );
					}

					if ( isset( $chunk['usage'] ) ) {
						$accumulated_usage = $chunk['usage'];
					}
				}

				return strlen( $data );
			},
			CURLOPT_HTTPHEADER => array(
				'Authorization: Bearer ' . $this->api_key,
				'Content-Type: application/json',
			),
			CURLOPT_POSTFIELDS => wp_json_encode( $body ),
			CURLOPT_TIMEOUT => 180,
		) );

		$start_time = microtime( true );
		$result = curl_exec( $ch );
		$http_code = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
		$curl_error = curl_error( $ch );
		curl_close( $ch );

		if ( false === $result && ! empty( $curl_error ) ) {
			return new WP_Error( 'curl_error', 'cURL error: ' . $curl_error );
		}

		if ( $http_code >= 400 ) {
			return new WP_Error( 'api_error', sprintf( 'API error (%d)', $http_code ) );
		}

		$cost = $this->calculate_cost( $model, $accumulated_usage );

		return array(
			'content' => $accumulated_content,
			'model' => $model,
			'input_tokens' => $accumulated_usage['prompt_tokens'] ?? 0,
			'output_tokens' => $accumulated_usage['completion_tokens'] ?? 0,
			'total_tokens' => $accumulated_usage['total_tokens'] ?? 0,
			'cost' => $cost,
			'generation_time' => microtime( true ) - $start_time,
		);
	}

	/**
	 * Generate image (not supported by Codex)
	 *
	 * @param string $prompt Image prompt.
	 * @param string $model  Model to use.
	 * @param array  $options Optional parameters.
	 * @return WP_Error Error indicating not supported.
	 */
	public function generate_image( $prompt, $model = null, $options = array() ) {
		return new WP_Error(
			'not_supported',
			__( 'Image generation not supported by Codex. Use OpenRouter for images.', 'wp-agentic-writer' )
		);
	}

	/**
	 * Check if provider is configured
	 *
	 * @return bool True if API key is set.
	 */
	public function is_configured() {
		return ! empty( $this->api_key );
	}

	/**
	 * Test connection to Codex API
	 *
	 * @return array|WP_Error Success array or error.
	 */
	public function test_connection() {
		if ( ! $this->is_configured() ) {
			return new WP_Error( 'not_configured', 'Codex API key not configured' );
		}

		$response = wp_remote_post(
			$this->api_endpoint,
			array(
				'headers' => array(
					'Authorization' => 'Bearer ' . $this->api_key,
					'Content-Type' => 'application/json',
				),
				'body' => wp_json_encode(
					array(
						'model' => $this->model,
						'messages' => array(
							array(
								'role' => 'user',
								'content' => 'Reply with: Test successful',
							),
						),
						'max_tokens' => 10,
					)
				),
				'timeout' => 15,
			)
		);

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

		$code = wp_remote_retrieve_response_code( $response );
		if ( 200 !== $code ) {
			$body = json_decode( wp_remote_retrieve_body( $response ), true );
			return new WP_Error(
				'connection_failed',
				$body['error']['message'] ?? sprintf( 'API returned status %d', $code )
			);
		}

		return array(
			'success' => true,
			'message' => 'Connected to OpenAI Codex successfully',
		);
	}

	/**
	 * Check if provider supports task type
	 *
	 * @param string $type Task type.
	 * @return bool True if supported (all text tasks).
	 */
	public function supports_task_type( $type ) {
		return in_array(
			$type,
			array( 'chat', 'clarity', 'planning', 'writing', 'refinement' ),
			true
		);
	}

	/**
	 * Calculate cost based on OpenAI pricing
	 *
	 * @param string $model Model identifier.
	 * @param array  $usage Usage data with prompt_tokens and completion_tokens.
	 * @return float Cost in USD.
	 */
	private function calculate_cost( $model, $usage ) {
		if ( empty( $usage['prompt_tokens'] ) && empty( $usage['completion_tokens'] ) ) {
			return 0;
		}

		// OpenAI pricing (as of 2024, per 1M tokens)
		$pricing = array(
			'gpt-4o' => array( 'input' => 2.50, 'output' => 10.00 ),
			'gpt-4o-mini' => array( 'input' => 0.15, 'output' => 0.60 ),
			'gpt-4-turbo' => array( 'input' => 10.00, 'output' => 30.00 ),
			'gpt-4' => array( 'input' => 30.00, 'output' => 60.00 ),
			'gpt-3.5-turbo' => array( 'input' => 0.50, 'output' => 1.50 ),
		);

		$rates = $pricing[ $model ] ?? $pricing['gpt-4o'];

		$input_cost = ( $usage['prompt_tokens'] ?? 0 ) * ( $rates['input'] / 1000000 );
		$output_cost = ( $usage['completion_tokens'] ?? 0 ) * ( $rates['output'] / 1000000 );

		return $input_cost + $output_cost;
	}
}
