<?php
/**
 * Netcore Email API provider (formerly Pepipost) — API v6.
 *
 * @package EmailSmtp
 * @link https://emaildocs.netcorecloud.com/docs/getting-started
 * @link https://emaildocs.netcorecloud.com/reference/sendmail
 */

namespace EmailSmtp\Providers\Netcore;

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 {

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

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

	public function get_description(): string {
		return __( 'Send email through the Netcore Email API (formerly Pepipost).', 'wp-powersuite' );
	}

	public function get_docs_url(): string {
		return 'https://emaildocs.netcorecloud.com/docs/getting-started';
	}

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

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


	/**
	 * @param array<string, mixed> $settings
	 */
	private function api_base( array $settings ): string {
		$region = sanitize_key( (string) ( $settings['netcore_region'] ?? 'us' ) );
		return $region === 'eu'
			? 'https://apieu.netcorecloud.net/v6'
			: 'https://emailapi.netcorecloud.net/v6';
	}

	/**
	 * V6 OpenAPI uses Bearer; legacy Pepipost clients also sent api_key.
	 *
	 * @return array<string, string>
	 */
	private function auth_headers( string $key ): array {
		return [
			'Content-Type'  => 'application/json',
			'Authorization' => 'Bearer ' . $key,
			'api_key'       => $key,
		];
	}

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

		// Probe /mail/send with invalid addresses: 401 = bad key, 400 = auth OK.
		$response = ApiHttpClient::request(
			'POST',
			$this->api_base( $settings ) . '/mail/send',
			$this->auth_headers( $key ),
			[
				'from'             => [ 'email' => 'invalid@invalid' ],
				'personalizations' => [
					[ 'to' => [ [ 'email' => 'invalid@invalid' ] ] ],
				],
				'subject'          => 'connection-test',
				'content'          => [
					[ 'type' => 'html', 'value' => 'connection-test' ],
				],
			]
		);

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

		$code = (int) ( $response['code'] ?? 0 );
		if ( $code === 401 ) {
			$technical = ApiHttpClient::extract_error_text( $response );
			$result    = ErrorNormalizer::from_text( $technical, '401' );
			return DeliveryResult::failure(
				__( 'Netcore rejected the API key.', 'wp-powersuite' ),
				$result->get_technical_message(),
				'authentication',
				'401',
				false,
				__( 'Check the API key and region (US vs EU) in your Netcore Email API account.', 'wp-powersuite' ),
				(int) ( $response['duration_ms'] ?? 0 )
			);
		}

		if ( in_array( $code, [ 400, 200, 202 ], true ) ) {
			return DeliveryResult::success(
				__( 'Netcore API key authenticated successfully.', 'wp-powersuite' ),
				'',
				(int) ( $response['duration_ms'] ?? 0 )
			);
		}

		return ApiHttpClient::to_delivery_result( $response, null, 200, 299 );
	}

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

		$key = $this->secret( $settings, 'netcore_api_key', 'WP_POWERSUITE_NETCORE_API_KEY' );
		if ( $key === '' ) {
			return DeliveryResult::failure( __( 'Netcore API key is required.', 'wp-powersuite' ), '', 'authentication' );
		}

		$from = $this->from_parts( $message );

		$personalizations = [
			'to' => array_map(
				static fn( string $email ) => [ 'email' => $email ],
				$message->get_to()
			),
		];
		if ( $message->get_cc() !== [] ) {
			$personalizations['cc'] = array_map(
				static fn( string $email ) => [ 'email' => $email ],
				$message->get_cc()
			);
		}
		if ( $message->get_bcc() !== [] ) {
			$personalizations['bcc'] = array_map(
				static fn( string $email ) => [ 'email' => $email ],
				$message->get_bcc()
			);
		}

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

		// V6 content types are html | amp (plain text sent as escaped HTML).
		if ( $message->is_html() ) {
			$content = [
				[ 'type' => 'html', 'value' => $message->get_body() ],
			];
		} else {
			$content = [
				[
					'type'  => 'html',
					'value' => nl2br( esc_html( $message->get_body() ), false ),
				],
			];
		}

		$from_obj = [ 'email' => $from['email'] ];
		if ( $from['name'] !== '' ) {
			$from_obj['name'] = $from['name'];
		}

		$payload = [
			'from'             => $from_obj,
			'personalizations' => [ $personalizations ],
			'subject'          => $message->get_subject(),
			'content'          => $content,
			'priorityflag'     => 1, // Transactional / OTP priority.
		];

		if ( is_email( $message->get_reply_to_email() ) ) {
			$reply = [ 'email' => $message->get_reply_to_email() ];
			if ( $message->get_reply_to_name() !== '' ) {
				$reply['name'] = $message->get_reply_to_name();
			}
			// V6: reply_to is an array of address objects.
			$payload['reply_to'] = [ $reply ];
		}

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

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

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