<?php
/**
 * SMTP2GO email API provider.
 *
 * @package EmailSmtp
 * @link https://developers.smtp2go.com/docs/send-an-email
 * @link https://developers.smtp2go.com/docs/endpoints
 */

namespace EmailSmtp\Providers\Smtp2go;

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 {

	/** Max recipients per role on /email/send. */
	private const RECIPIENT_CAP = 100;

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

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

	public function get_description(): string {
		return __( 'Send email through the SMTP2GO REST API v3.', 'wp-powersuite' );
	}

	public function get_docs_url(): string {
		return 'https://developers.smtp2go.com/docs/send-an-email';
	}

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

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


	/**
	 * @param array<string, mixed> $settings
	 */
	private function base_url( array $settings ): string {
		$region = sanitize_key( (string) ( $settings['smtp2go_region'] ?? 'global' ) );
		return match ( $region ) {
			'us'    => 'https://us-api.smtp2go.com/v3',
			'eu'    => 'https://eu-api.smtp2go.com/v3',
			'au'    => 'https://au-api.smtp2go.com/v3',
			default => 'https://api.smtp2go.com/v3',
		};
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, string>
	 */
	private function auth_headers( array $settings ): array {
		$key = $this->secret( $settings, 'smtp2go_api_key', 'WP_POWERSUITE_SMTP2GO_API_KEY' );
		return [
			'Content-Type'      => 'application/json',
			'X-Smtp2go-Api-Key' => $key,
		];
	}

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

		// Available to all API keys (unlike stats endpoints).
		$response = ApiHttpClient::request(
			'POST',
			$this->base_url( $settings ) . '/api_keys/permissions',
			$this->auth_headers( $settings ),
			[]
		);

		return ApiHttpClient::to_delivery_result(
			$response,
			static function () {
				return [ 'message' => __( 'SMTP2GO 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, 'smtp2go_api_key', 'WP_POWERSUITE_SMTP2GO_API_KEY' );
		if ( $key === '' ) {
			return DeliveryResult::failure( __( 'SMTP2GO API key is required.', 'wp-powersuite' ), '', 'authentication' );
		}

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

		if ( $message->is_html() ) {
			$payload['html_body'] = $message->get_body();
			$payload['text_body'] = $message->get_alt_body() !== ''
				? $message->get_alt_body()
				: wp_strip_all_tags( $message->get_body() );
		} else {
			$payload['text_body'] = $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 );
		}

		$custom_headers = [];
		if ( is_email( $message->get_reply_to_email() ) ) {
			$custom_headers[] = [
				'header' => 'Reply-To',
				'value'  => $this->format_address( $message->get_reply_to_email(), $message->get_reply_to_name() ),
			];
		}
		foreach ( $this->safe_custom_headers( $message ) as $header => $value ) {
			if ( strtolower( (string) $header ) === 'reply-to' ) {
				continue;
			}
			$custom_headers[] = [
				'header' => (string) $header,
				'value'  => (string) $value,
			];
		}
		if ( $custom_headers !== [] ) {
			$payload['custom_headers'] = $custom_headers;
		}

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

		$response = ApiHttpClient::request(
			'POST',
			$this->base_url( $settings ) . '/email/send',
			$this->auth_headers( $settings ),
			$payload
		);

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

		$code = (int) ( $response['code'] ?? 0 );
		$json = $response['json'] ?? null;

		// HTTP 200 can still report per-recipient failures when fastaccept is off (default).
		if ( $code >= 200 && $code <= 299 && is_array( $json ) && isset( $json['data'] ) && is_array( $json['data'] ) ) {
			$data     = $json['data'];
			$failed   = (int) ( $data['failed'] ?? 0 );
			$succeeded = (int) ( $data['succeeded'] ?? 0 );

			if ( $failed > 0 || ( isset( $data['succeeded'] ) && $succeeded < 1 ) ) {
				$parts = [];
				if ( ! empty( $data['failures'] ) && is_array( $data['failures'] ) ) {
					foreach ( $data['failures'] as $failure ) {
						if ( is_string( $failure ) && $failure !== '' ) {
							$parts[] = $failure;
						} elseif ( is_array( $failure ) ) {
							$parts[] = (string) ( $failure['error'] ?? $failure['message'] ?? wp_json_encode( $failure ) );
						}
					}
				}
				if ( ! empty( $data['error'] ) && is_string( $data['error'] ) ) {
					array_unshift( $parts, $data['error'] );
				}
				$technical = $parts !== []
					? implode( '; ', $parts )
					: __( 'SMTP2GO rejected one or more recipients.', 'wp-powersuite' );
				$result = ErrorNormalizer::from_text( $technical, (string) $code );
				return DeliveryResult::failure(
					$result->get_user_message(),
					$result->get_technical_message(),
					$result->get_category(),
					(string) $code,
					$result->is_retry_safe(),
					__( 'Verify the sender is authorised and recipients are not suppressed.', 'wp-powersuite' ),
					(int) ( $response['duration_ms'] ?? 0 )
				);
			}

			$id = '';
			if ( isset( $data['email_id'] ) ) {
				$ids = $data['email_id'];
				$id  = is_array( $ids ) ? (string) ( $ids[0] ?? '' ) : (string) $ids;
			}

			return DeliveryResult::success(
				__( 'SMTP2GO accepted the message.', 'wp-powersuite' ),
				$id,
				(int) ( $response['duration_ms'] ?? 0 )
			);
		}

		return ApiHttpClient::to_delivery_result(
			$response,
			static function () {
				return [ 'message' => __( 'SMTP2GO accepted the message.', 'wp-powersuite' ) ];
			}
		);
	}
}
