<?php
/**
 * SparkPost / Bird Email API provider.
 *
 * Bird Email (formerly SparkPost) uses POST /v1/email/messages with Bearer bk_{region}_… keys.
 * Legacy SparkPost API keys continue to use /api/v1/transmissions.
 *
 * @package EmailSmtp
 * @link https://bird.com/en-us/docs/api
 * @link https://bird.com/en-us/docs/guides/email/sending-email
 */

namespace EmailSmtp\Providers\Sparkpost;

use EmailSmtp\Includes\AbstractApiProvider;
use EmailSmtp\Includes\ApiHttpClient;
use EmailSmtp\Includes\DeliveryResult;
use EmailSmtp\Includes\EmailMessage;
use EmailSmtp\Includes\ErrorNormalizer;

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

final class Provider extends AbstractApiProvider {

	private const RECIPIENT_CAP = 50;

	public function get_id(): string {
		return 'sparkpost';
	}

	public function get_name(): string {
		return __( 'SparkPost', 'wp-powersuite' );
	}

	public function get_description(): string {
		return __( 'Send transactional email through Bird Email (SparkPost) API.', 'wp-powersuite' );
	}

	public function get_docs_url(): string {
		return 'https://bird.com/en-us/docs/api';
	}

	public function get_icon(): string {
		return 'dashicons-email-alt';
	}

	public function get_required_fields(): array {
		return [ 'sparkpost_api_key' ];
	}


	/**
	 * Bird platform keys: bk_{region}_{payload}{checksum}.
	 */
	private function is_bird_key( string $key ): bool {
		return (bool) preg_match( '/^bk_[a-z]{2}\d+_/i', $key );
	}

	/**
	 * @param array<string, mixed> $settings
	 */
	private function bird_base( string $key, array $settings ): string {
		if ( preg_match( '/^bk_([a-z]{2}\d+)_/i', $key, $m ) ) {
			$region = strtolower( $m[1] );
			return 'https://' . $region . '.platform.bird.com';
		}
		$setting = sanitize_key( (string) ( $settings['sparkpost_region'] ?? 'us' ) );
		return $setting === 'eu' ? 'https://eu1.platform.bird.com' : 'https://us1.platform.bird.com';
	}

	/**
	 * @param array<string, mixed> $settings
	 */
	private function classic_base( array $settings ): string {
		$region = sanitize_key( (string) ( $settings['sparkpost_region'] ?? 'us' ) );
		return $region === 'eu' ? 'https://api.eu.sparkpost.com' : 'https://api.sparkpost.com';
	}

	public function connect( array $settings ): DeliveryResult {
		$key = $this->secret( $settings, 'sparkpost_api_key', 'WP_POWERSUITE_SPARKPOST_API_KEY' );
		if ( $key === '' ) {
			return DeliveryResult::failure( __( 'SparkPost / Bird API key is required.', 'wp-powersuite' ), '', 'authentication' );
		}

		if ( $this->is_bird_key( $key ) ) {
			$response = ApiHttpClient::request(
				'GET',
				$this->bird_base( $key, $settings ) . '/v1/email/messages?limit=1',
				[
					'Authorization' => 'Bearer ' . $key,
					'Content-Type'  => 'application/json',
				]
			);

			return ApiHttpClient::to_delivery_result(
				$response,
				static function () {
					return [ 'message' => __( 'Bird Email API key authenticated successfully.', 'wp-powersuite' ) ];
				}
			);
		}

		$response = ApiHttpClient::request(
			'GET',
			$this->classic_base( $settings ) . '/api/v1/account',
			[ 'Authorization' => $key ]
		);

		return ApiHttpClient::to_delivery_result(
			$response,
			static function () {
				return [ 'message' => __( 'SparkPost API key authenticated successfully.', 'wp-powersuite' ) ];
			}
		);
	}

	public function send( EmailMessage $message, array $settings ): DeliveryResult {
		$missing = $this->require_from( $message );
		if ( $missing ) {
			return $missing;
		}

		$key = $this->secret( $settings, 'sparkpost_api_key', 'WP_POWERSUITE_SPARKPOST_API_KEY' );
		if ( $key === '' ) {
			return DeliveryResult::failure( __( 'SparkPost / Bird API key is required.', 'wp-powersuite' ), '', 'authentication' );
		}

		return $this->is_bird_key( $key )
			? $this->send_bird( $message, $settings, $key )
			: $this->send_classic( $message, $settings, $key );
	}

	/**
	 * Bird Email: POST /v1/email/messages (202 Accepted).
	 *
	 * @param array<string, mixed> $settings
	 */
	private function send_bird( EmailMessage $message, array $settings, string $key ): DeliveryResult {
		$from = $this->from_parts( $message );

		$payload = [
			'from'     => $this->format_address( $from['email'], $from['name'] ),
			'to'       => array_slice( $message->get_to(), 0, self::RECIPIENT_CAP ),
			'subject'  => $message->get_subject(),
			'category' => 'transactional',
		];

		if ( $message->is_html() ) {
			$payload['html'] = $message->get_body();
			$payload['text'] = $message->get_alt_body() !== ''
				? $message->get_alt_body()
				: wp_strip_all_tags( $message->get_body() );
		} else {
			$payload['text'] = $message->get_body();
		}

		if ( $message->get_cc() !== [] ) {
			$payload['cc'] = array_slice( $message->get_cc(), 0, self::RECIPIENT_CAP );
		}
		if ( $message->get_bcc() !== [] ) {
			$payload['bcc'] = array_slice( $message->get_bcc(), 0, self::RECIPIENT_CAP );
		}
		if ( is_email( $message->get_reply_to_email() ) ) {
			$payload['reply_to'] = [
				$this->format_address( $message->get_reply_to_email(), $message->get_reply_to_name() ),
			];
		}

		$headers = $this->safe_custom_headers( $message );
		if ( $headers !== [] ) {
			$payload['headers'] = $headers;
		}

		$attachments = $this->attachments_as_base64( $message );
		if ( $attachments !== [] ) {
			$payload['attachments'] = array_map(
				static function ( array $a ) {
					$row = [
						'filename' => $a['name'],
						'content'  => $a['content'],
					];
					if ( $a['type'] !== '' ) {
						$row['content_type'] = $a['type'];
					}
					return $row;
				},
				array_slice( $attachments, 0, 20 )
			);
		}

		$response = ApiHttpClient::request(
			'POST',
			$this->bird_base( $key, $settings ) . '/v1/email/messages',
			[
				'Authorization'   => 'Bearer ' . $key,
				'Content-Type'    => 'application/json',
				'Idempotency-Key' => wp_generate_uuid4(),
			],
			$payload
		);

		if ( ! empty( $response['error'] ) ) {
			return ErrorNormalizer::from_text( (string) $response['error'] );
		}

		return ApiHttpClient::to_delivery_result(
			$response,
			static function ( array $res ) {
				$id = '';
				if ( is_array( $res['json'] ) ) {
					$id = (string) ( $res['json']['id'] ?? '' );
				}
				return [
					'message' => __( 'Bird Email accepted the message.', 'wp-powersuite' ),
					'id'      => $id,
				];
			}
		);
	}

	/**
	 * Legacy SparkPost transmissions API.
	 *
	 * @param array<string, mixed> $settings
	 */
	private function send_classic( EmailMessage $message, array $settings, string $key ): DeliveryResult {
		$from       = $this->from_parts( $message );
		$recipients = [];
		foreach ( array_slice( $message->get_to(), 0, self::RECIPIENT_CAP ) as $email ) {
			$recipients[] = [ 'address' => [ 'email' => $email ] ];
		}
		$header_to = implode( ',', $message->get_to() );
		foreach ( array_slice( $message->get_cc(), 0, self::RECIPIENT_CAP ) as $email ) {
			$recipients[] = [
				'address'   => [ 'email' => $email ],
				'header_to' => $header_to,
			];
		}
		foreach ( array_slice( $message->get_bcc(), 0, self::RECIPIENT_CAP ) as $email ) {
			$recipients[] = [
				'address'   => [ 'email' => $email ],
				'header_to' => $header_to,
			];
		}

		$content = [
			'from'    => $this->format_address( $from['email'], $from['name'] ),
			'subject' => $message->get_subject(),
		];
		if ( $message->is_html() ) {
			$content['html'] = $message->get_body();
			$content['text'] = $message->get_alt_body() !== ''
				? $message->get_alt_body()
				: wp_strip_all_tags( $message->get_body() );
		} else {
			$content['text'] = $message->get_body();
		}
		if ( is_email( $message->get_reply_to_email() ) ) {
			$content['reply_to'] = $this->format_address( $message->get_reply_to_email(), $message->get_reply_to_name() );
		}

		$headers = $this->safe_custom_headers( $message );
		if ( $headers !== [] ) {
			$content['headers'] = $headers;
		}

		$attachments = $this->attachments_as_base64( $message );
		if ( $attachments !== [] ) {
			$content['attachments'] = array_map(
				static function ( array $a ) {
					return [
						'name' => $a['name'],
						'type' => $a['type'] !== '' ? $a['type'] : 'application/octet-stream',
						'data' => $a['content'],
					];
				},
				$attachments
			);
		}

		$response = ApiHttpClient::request(
			'POST',
			$this->classic_base( $settings ) . '/api/v1/transmissions',
			[ 'Authorization' => $key ],
			[
				'options'    => [ 'sandbox' => false ],
				'content'    => $content,
				'recipients' => $recipients,
			]
		);

		return ApiHttpClient::to_delivery_result(
			$response,
			static function ( array $res ) {
				$id = '';
				if ( is_array( $res['json'] ) ) {
					$id = (string) ( $res['json']['results']['id'] ?? '' );
				}
				return [
					'message' => __( 'SparkPost accepted the message.', 'wp-powersuite' ),
					'id'      => $id,
				];
			}
		);
	}
}
