<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Soap\ExtSoapEngine;

use Gls\GlsPoland\Soap\Engine\DecoderInterface;
use Gls\GlsPoland\Soap\Engine\DriverInterface;
use Gls\GlsPoland\Soap\Engine\EncoderInterface;
use Gls\GlsPoland\Soap\Engine\HttpBinding\SoapRequest;
use Gls\GlsPoland\Soap\Engine\HttpBinding\SoapResponse;
use Gls\GlsPoland\Soap\Engine\Metadata\LazyInMemoryMetadata;
use Gls\GlsPoland\Soap\Engine\Metadata\MetadataInterface;
use Gls\GlsPoland\Soap\ExtSoapEngine\Generator\DummyMethodArgumentsGenerator;

final class ExtSoapDriver implements DriverInterface
{
    /**
     * @var AbusedClient
     */
    private $client;
    /**
     * @var EncoderInterface
     */
    private $encoder;
    /**
     * @var DecoderInterface
     */
    private $decoder;
    /**
     * @var MetadataInterface
     */
    private $metadata;

    public function __construct(
        AbusedClient $client,
        EncoderInterface $encoder,
        DecoderInterface $decoder,
        MetadataInterface $metadata
    ) {
        $this->client = $client;
        $this->encoder = $encoder;
        $this->decoder = $decoder;
        $this->metadata = $metadata;
    }

    public static function createFromOptions(ExtSoapOptions $options): self
    {
        $client = AbusedClient::createFromOptions($options);

        return self::createFromClient(
            $client,
            new LazyInMemoryMetadata(new ExtSoapMetadata($client))
        );
    }

    public static function createFromClient(AbusedClient $client, ?MetadataInterface $metadata = null): self
    {
        $metadata = $metadata ?? new LazyInMemoryMetadata(new ExtSoapMetadata($client));

        return new self(
            $client,
            new ExtSoapEncoder($client),
            new ExtSoapDecoder($client, new DummyMethodArgumentsGenerator($metadata)),
            $metadata
        );
    }

    public function decode(string $method, SoapResponse $response)
    {
        return $this->decoder->decode($method, $response);
    }

    public function encode(string $method, array $arguments): SoapRequest
    {
        return $this->encoder->encode($method, $arguments);
    }

    public function getMetadata(): MetadataInterface
    {
        return $this->metadata;
    }

    public function getClient(): AbusedClient
    {
        return $this->client;
    }
}
