<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Soap\ExtSoapEngine;

use Gls\GlsPoland\Soap\Engine\HttpBinding\SoapRequest;
use Gls\GlsPoland\Soap\Engine\HttpBinding\SoapResponse;
use Gls\GlsPoland\Soap\ExtSoapEngine\ErrorHandling\ExtSoapErrorHandler;
use Gls\GlsPoland\Soap\ExtSoapEngine\Exception\RequestException;

final class AbusedClient extends \SoapClient
{
    /**
     * @var SoapRequest|null
     */
    private $storedRequest;

    /**
     * @var SoapResponse|null
     */
    private $storedResponse;

    /**
     * Internal SoapClient property for storing last request.
     *
     * @var string
     */
    protected $__last_request = '';

    /**
     * Internal SoapClient property for storing last response.
     *
     * @var string
     */
    protected $__last_response = '';

    public function __construct(?string $wsdl, array $options = [])
    {
        $options = ExtSoapOptionsResolverFactory::createForWsdl($wsdl)->resolve($options);
        parent::__construct($wsdl, $options);
    }

    public static function createFromOptions(ExtSoapOptions $options): self
    {
        return new self($options->getWsdl(), $options->getOptions());
    }

    /**
     * @param string $request
     * @param string $location
     * @param string $action
     * @param int $version
     * @param bool|int $oneWay
     * @param string|null $uriParserClass
     */
    public function __doRequest($request, $location, $action, $version, $oneWay = false, $uriParserClass = null): ?string
    {
        $this->storedRequest = new SoapRequest($request, $location, $action, $version, (bool) $oneWay);

        return $this->storedResponse ? $this->storedResponse->getPayload() : '';
    }

    public function doActualRequest(
        string $request,
        string $location,
        string $action,
        int $version,
        bool $oneWay = false
    ): string {
        $this->__last_request = $request;
        $this->__last_response = (string) ExtSoapErrorHandler::handleNullResponse(
            ExtSoapErrorHandler::handleInternalErrors(
                function () use ($request, $location, $action, $version, $oneWay): ?string {
                    $oneWay = 80000 > PHP_VERSION_ID ? (int) $oneWay : $oneWay;

                    if (PHP_VERSION_ID >= 80400) {
                        return parent::__doRequest($request, $location, $action, $version, $oneWay, null);
                    }

                    return parent::__doRequest($request, $location, $action, $version, $oneWay);
                }
            )
        );

        return $this->__last_response;
    }

    public function collectRequest(): SoapRequest
    {
        if (!$this->storedRequest) {
            throw RequestException::noRequestRegistered();
        }

        return $this->storedRequest;
    }

    public function registerResponse(SoapResponse $response): void
    {
        $this->storedResponse = $response;
    }

    public function cleanUpTemporaryState(): void
    {
        $this->storedRequest = null;
        $this->storedResponse = null;
    }

    public function __getLastRequest(): string
    {
        return $this->__last_request;
    }

    public function __getLastResponse(): string
    {
        return $this->__last_response;
    }
}
