<?php
/**
 * Anthropic Claude vision provider.
 *
 * @package AIAltTextGenerator
 * @since 1.6.0
 */

namespace AIAltTextGenerator\Providers;

use AIAltTextGenerator\Settings;

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

/**
 * @since 1.6.0
 */
class ClaudeProvider implements ProviderInterface {

	public function getId(): string {
		return 'claude';
	}

	public function getLabel(): string {
		return 'Claude';
	}

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

	/**
	 * @param array<string, mixed> $options
	 * @return array{alt_text: string, tokens: int}|\WP_Error
	 */
	public function generate( string $file_path, array $options = [] ): array|\WP_Error {
		$api_key = (string) ( $options['api_key'] ?? Settings::getApiKey( null, 'claude' ) );
		if ( $api_key === '' ) {
			return new \WP_Error( 'missing_api_key', __( 'Claude API key is not configured.', 'wp-powersuite' ) );
		}

		$model        = (string) ( $options['model'] ?? 'claude-haiku-4-5-20251001' );
		$max_chars    = (int) ( $options['max_chars'] ?? 125 );
		$prompt_style = (string) ( $options['prompt_style'] ?? 'concise' );
		$language     = (string) ( $options['language'] ?? '' );
		$custom_prompt = trim( (string) ( $options['custom_prompt'] ?? '' ) );
		$context      = is_array( $options['context'] ?? null ) ? $options['context'] : [];

		if ( ! is_file( $file_path ) ) {
			return new \WP_Error( 'file_not_found', __( 'Image file not found.', 'wp-powersuite' ) );
		}

		$attachment_id = max( 0, (int) ( $options['attachment_id'] ?? 0 ) );
		$mime          = VisionHelper::detectMime( $file_path, $attachment_id );

		if ( $mime === VisionHelper::SVG_MIME ) {
			return $this->generateForSvg( $file_path, $api_key, $model, $max_chars, $prompt_style, $language, $custom_prompt, $context, $options );
		}

		if ( ! VisionHelper::isProcessableMime( $mime ) ) {
			return new \WP_Error( 'unsupported_format', __( 'Unsupported image format for Claude.', 'wp-powersuite' ) );
		}

		$max_dimension = max( 0, (int) ( $options['max_dimension'] ?? 0 ) );
		if ( ! empty( $options['force_jpeg'] ) ) {
			$payload = VisionHelper::convertToApiPayload(
				$file_path,
				'image/jpeg',
				$max_dimension > 0 ? $max_dimension : VisionHelper::BULK_MAX_DIMENSION
			);
		} else {
			$payload = VisionHelper::getApiImagePayload( $file_path, $mime, null, $max_dimension );
		}
		if ( is_wp_error( $payload ) ) {
			return $payload;
		}

		$prompt = VisionHelper::buildSystemPrompt( $max_chars, $prompt_style, $language, $custom_prompt, $context );
		$prompt = (string) apply_filters( 'wpps_ai_alt_text_prompt', $prompt, $attachment_id, $context );

		$body = [
			'model'      => $model,
			'max_tokens' => 200,
			'messages'   => [
				[
					'role'    => 'user',
					'content' => [
						[
							'type'   => 'image',
							'source' => [
								'type'       => 'base64',
								'media_type' => $payload['mime'],
								'data'       => $payload['data'],
							],
						],
						[
							'type' => 'text',
							'text' => $prompt,
						],
					],
				],
			],
		];

		$response = wp_remote_post(
			'https://api.anthropic.com/v1/messages',
			[
				'timeout' => max( 10, min( 180, (int) ( $options['timeout'] ?? 90 ) ) ),
				'headers' => [
					'x-api-key'         => $api_key,
					'anthropic-version' => '2023-06-01',
					'content-type'      => 'application/json',
				],
				'body' => wp_json_encode( $body ),
			]
		);

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

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

		if ( $code !== 200 || ! is_array( $decoded ) ) {
			$message = is_array( $decoded ) ? ( $decoded['error']['message'] ?? __( 'Claude API error.', 'wp-powersuite' ) ) : __( 'Claude API error.', 'wp-powersuite' );
			$classified = \AIAltTextGenerator\GenerationError::classify( 'api_error', (string) $message, (int) $code );

			return new \WP_Error(
				$classified['code'],
				$classified['message'],
				[ 'status' => (int) $code ]
			);
		}

		$content = '';
		foreach ( (array) ( $decoded['content'] ?? [] ) as $part ) {
			if ( is_array( $part ) && ( $part['type'] ?? '' ) === 'text' ) {
				$content .= (string) ( $part['text'] ?? '' );
			}
		}

		$tokens = (int) ( $decoded['usage']['input_tokens'] ?? 0 ) + (int) ( $decoded['usage']['output_tokens'] ?? 0 );
		$alt    = VisionHelper::normalizeAltText( $content, $max_chars );

		if ( $alt === '' ) {
			return new \WP_Error( 'empty_response', __( 'AI returned empty alt text.', 'wp-powersuite' ) );
		}

		return [ 'alt_text' => $alt, 'tokens' => $tokens ];
	}

	/**
	 * @param array<string, mixed> $context
	 * @param array<string, mixed> $options
	 * @return array{alt_text: string, tokens: int}|\WP_Error
	 */
	private function generateForSvg( string $file_path, string $api_key, string $model, int $max_chars, string $prompt_style, string $language, string $custom_prompt, array $context, array $options ): array|\WP_Error {
		$user_content = VisionHelper::readSvgUserContent( $file_path );
		if ( is_wp_error( $user_content ) ) {
			return $user_content;
		}

		$attachment_id = max( 0, (int) ( $options['attachment_id'] ?? 0 ) );
		$prompt        = VisionHelper::buildSystemPrompt( $max_chars, $prompt_style, $language, $custom_prompt, $context );
		$prompt       .= VisionHelper::svgPromptSuffix();
		$prompt        = (string) apply_filters( 'wpps_ai_alt_text_prompt', $prompt, $attachment_id, $context );

		$body = [
			'model'      => $model,
			'max_tokens' => 200,
			'messages'   => [
				[
					'role'    => 'user',
					'content' => [
						[
							'type' => 'text',
							'text' => $prompt . "\n\n" . $user_content,
						],
					],
				],
			],
		];

		$response = wp_remote_post(
			'https://api.anthropic.com/v1/messages',
			[
				'timeout' => max( 10, min( 180, (int) ( $options['timeout'] ?? 90 ) ) ),
				'headers' => [
					'x-api-key'         => $api_key,
					'anthropic-version' => '2023-06-01',
					'content-type'      => 'application/json',
				],
				'body' => wp_json_encode( $body ),
			]
		);

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

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

		if ( $code !== 200 || ! is_array( $decoded ) ) {
			$message = is_array( $decoded ) ? ( $decoded['error']['message'] ?? __( 'Claude API error.', 'wp-powersuite' ) ) : __( 'Claude API error.', 'wp-powersuite' );
			$classified = \AIAltTextGenerator\GenerationError::classify( 'api_error', (string) $message, (int) $code );

			return new \WP_Error(
				$classified['code'],
				$classified['message'],
				[ 'status' => (int) $code ]
			);
		}

		$content = '';
		foreach ( (array) ( $decoded['content'] ?? [] ) as $part ) {
			if ( is_array( $part ) && ( $part['type'] ?? '' ) === 'text' ) {
				$content .= (string) ( $part['text'] ?? '' );
			}
		}

		$tokens = (int) ( $decoded['usage']['input_tokens'] ?? 0 ) + (int) ( $decoded['usage']['output_tokens'] ?? 0 );
		$alt    = VisionHelper::normalizeAltText( $content, $max_chars );

		if ( $alt === '' ) {
			return new \WP_Error( 'empty_response', __( 'AI returned empty alt text.', 'wp-powersuite' ) );
		}

		return [ 'alt_text' => $alt, 'tokens' => $tokens ];
	}

	/**
	 * @param array<string, mixed> $options
	 * @return true|\WP_Error
	 */
	public function testConnection( array $options = [] ): bool|\WP_Error {
		$api_key = (string) ( $options['api_key'] ?? Settings::getApiKey( null, 'claude' ) );
		if ( $api_key === '' ) {
			return new \WP_Error( 'missing_api_key', __( 'Claude API key is not configured.', 'wp-powersuite' ) );
		}

		$response = wp_remote_get(
			'https://api.anthropic.com/v1/models',
			[
				'timeout' => 20,
				'headers' => [
					'x-api-key'         => $api_key,
					'anthropic-version' => '2023-06-01',
				],
			]
		);

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

		if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
			return new \WP_Error( 'api_error', __( 'Claude API connection failed.', 'wp-powersuite' ) );
		}

		return true;
	}
}
