<?php
/**
 * Class LoggingSoapClient
 *
 * @package DhlPolska\API
 */

namespace DhlPolska\API;

use DhlPolskaVendor\Psr\Log\LoggerInterface;
use SoapClient;

/**
 * SoapClient with logging.
 */
class LoggingSoapClient extends SoapClient {

	private string $api;

	/**
	 * @var LoggerInterface
	 */
	private LoggerInterface $logger;

	/**
	 * LoggingSoapClient constructor.
	 *
	 * @param string          $api     .
	 * @param string|null     $wsdl    .
	 * @param array           $options .
	 * @param LoggerInterface $logger  .
	 */
	public function __construct( string $api, ?string $wsdl, array $options, LoggerInterface $logger ) {
		parent::__construct( $wsdl, $options );
		$this->logger = $logger;
		$this->api    = $api;
	}

	/**
	 * @param string $request  .
	 * @param string $location .
	 * @param string $action   .
	 * @param int    $version  .
	 * @param int    $one_way  .
	 *
	 * @return string|null
	 */
	#[\ReturnTypeWillChange]
	public function __doRequest( $request, $location, $action, $version, $one_way = 0 ) {
		$this->logger->debug( 'DHL ' . $this->api . ' request: ' . $this->mask_password( $request ) );
		$response = $this->do_request( $request, $location, $action, $version, $one_way );
		$this->logger->debug( 'DHL ' . $this->api . ' response: ' . $this->mask_label( $response ) );

		if ( $response && strpos( $response, '<h1>CException</h1>' ) !== false ) {
			preg_match( '/<p>(.*?)<\/p>/s', $response, $matches );
			$error_msg = isset( $matches[1] ) ? strip_tags( $matches[1] ) : $response;
			throw new \Exception( sprintf( 'DHL WebAPI error: %s', $error_msg ) );
		}

		return $response;
	}

	/**
	 * @param string $request  .
	 * @param string $location .
	 * @param string $action   .
	 * @param int    $version  .
	 * @param int    $one_way  .
	 *
	 * @return string|null
	 * @codeCoverageIgnore
	 */
	protected function do_request( $request, $location, $action, $version, $one_way = 0 ) {
		return parent::__doRequest( $request, $location, $action, $version, $one_way );
	}

	/**
	 * @param string $xml .
	 *
	 * @return string
	 */
	private function mask_label( ?string $xml ): string {
		$xml = (string) preg_replace( '/<labelContent>.*?<\/labelContent>/i', '<labelContent>labelContent</labelContent>', (string) $xml );
		$xml = (string) preg_replace( '/<labelData>.*?<\/labelData>/i', '<labelData>labelContent</labelData>', $xml );

		return $xml;
	}

	/**
	 * @param string $xml .
	 *
	 * @return string
	 */
	private function mask_password( string $xml ): string {
		return (string) preg_replace( '/<password>.*?<\/password>/i', '<password>***</password>', $xml );
	}

	/**
	 * @param string     $name
	 * @param array      $args
	 * @param array|null $options
	 * @param mixed      $input_headers
	 * @param array|null $output_headers
	 *
	 * @return mixed
	 */
	#[\ReturnTypeWillChange]
	public function __soapCall( $name, $args, $options = null, $input_headers = null, &$output_headers = null ) {
		$args = json_decode( (string) json_encode( $args ), true );

		return parent::__soapCall( $name, $args, $options, $input_headers, $output_headers );
	}
}
