<?php
/**
 * OpenAI provider implementation.
 *
 * Uses the Responses API for generation and citation checks (web_search tool).
 *
 * @package WPLens
 */

namespace WPLens\AI;

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

final class OpenAIProvider implements Provider {

	private const ENDPOINT = 'https://api.openai.com/v1/chat/completions';
	private const TIMEOUT  = 30;

	public function get_slug(): string {
		return 'openai';
	}

	public function get_label(): string {
		return __( 'OpenAI (ChatGPT)', 'lens-ai-visibility-monitor' );
	}

	public function get_api_key(): string {
		$keys = get_option( 'wplens_provider_keys', array() );
		if ( ! is_array( $keys ) || empty( $keys['openai'] ) ) {
			return '';
		}
		return \WPLens\Utils\Encryption::decrypt( (string) $keys['openai'] );
	}

	public function is_configured(): bool {
		return '' !== $this->get_api_key();
	}

	public function supports_citation_check(): bool {
		return true;
	}

	public function generate( string $system_prompt, string $user_prompt, array $opts = array() ): GenerationResult {
		$api_key = $this->get_api_key();
		if ( '' === $api_key ) {
			return GenerationResult::error( 'no_key', __( 'No OpenAI API key configured.', 'lens-ai-visibility-monitor' ) );
		}

		$model       = isset( $opts['model'] ) ? (string) $opts['model'] : 'gpt-4o-mini';
		$temperature = isset( $opts['temperature'] ) ? (float) $opts['temperature'] : 0.2;
		$max_tokens  = isset( $opts['max_tokens'] ) ? (int) $opts['max_tokens'] : 800;

		$body = array(
			'model'       => $model,
			'temperature' => $temperature,
			'max_tokens'  => $max_tokens,
			'messages'    => array(
				array( 'role' => 'system', 'content' => $system_prompt ),
				array( 'role' => 'user', 'content' => $user_prompt ),
			),
		);

		$response = wp_remote_post(
			self::ENDPOINT,
			array(
				'timeout' => self::TIMEOUT,
				'headers' => array(
					'Authorization' => 'Bearer ' . $api_key,
					'Content-Type'  => 'application/json',
				),
				'body'    => wp_json_encode( $body ),
			)
		);

		if ( is_wp_error( $response ) ) {
			return GenerationResult::error( 'http_error', $response->get_error_message() );
		}

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

		if ( 200 !== (int) $code ) {
			$msg = is_array( $json ) && isset( $json['error']['message'] )
				? (string) $json['error']['message']
				: sprintf( /* translators: %d HTTP status */ __( 'OpenAI returned HTTP %d', 'lens-ai-visibility-monitor' ), (int) $code );
			return GenerationResult::error( 'api_error_' . (int) $code, $msg );
		}

		$text          = isset( $json['choices'][0]['message']['content'] ) ? (string) $json['choices'][0]['message']['content'] : '';
		$input_tokens  = isset( $json['usage']['prompt_tokens'] ) ? (int) $json['usage']['prompt_tokens'] : null;
		$output_tokens = isset( $json['usage']['completion_tokens'] ) ? (int) $json['usage']['completion_tokens'] : null;

		return new GenerationResult( true, $text, $input_tokens, $output_tokens );
	}

	public function check_citation( string $query, string $target_domain ): CitationResult {
		$system = 'You are an SEO research assistant. Answer the user query as if you were ChatGPT search. Then list every distinct URL you would cite as a numbered list at the end, prefixed by "Sources:". Use real URLs only — do not invent.';
		$user   = $query;

		$result = $this->generate( $system, $user, array( 'max_tokens' => 600, 'temperature' => 0.1 ) );
		if ( ! $result->ok ) {
			return CitationResult::error( $result->error_code ?? 'unknown', $result->error_message ?? '' );
		}

		$urls    = $this->extract_urls( $result->text );
		$matched = null;
		$pos     = null;
		$norm    = $this->normalize_domain( $target_domain );

		foreach ( $urls as $i => $url ) {
			$host = strtolower( (string) wp_parse_url( $url, PHP_URL_HOST ) );
			if ( '' === $host ) {
				continue;
			}
			if ( $host === $norm || $this->ends_with( $host, '.' . $norm ) ) {
				$matched = $url;
				$pos     = $i + 1;
				break;
			}
		}

		return new CitationResult(
			true,
			null !== $matched,
			$pos,
			$matched,
			$urls,
			mb_substr( $result->text, 0, 2000 )
		);
	}

	private function extract_urls( string $text ): array {
		$urls = array();
		if ( preg_match_all( '#https?://[^\s\)\]\,"\'<>]+#i', $text, $matches ) ) {
			foreach ( $matches[0] as $m ) {
				$urls[] = rtrim( $m, '.,;:' );
			}
		}
		return array_values( array_unique( $urls ) );
	}

	private function normalize_domain( string $domain ): string {
		$domain = strtolower( trim( $domain ) );
		$domain = preg_replace( '#^https?://#', '', $domain );
		$domain = preg_replace( '#^www\.#', '', $domain );
		$slash  = strpos( $domain, '/' );
		if ( false !== $slash ) {
			$domain = substr( $domain, 0, $slash );
		}
		return $domain;
	}

	private function ends_with( string $haystack, string $needle ): bool {
		$len = strlen( $needle );
		return 0 === $len || ( substr( $haystack, -$len ) === $needle );
	}
}
