<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Soap\ExtSoapEngine\Metadata;

use Gls\GlsPoland\Soap\Engine\Metadata\Collection\PropertyCollection;
use Gls\GlsPoland\Soap\Engine\Metadata\Collection\TypeCollection;
use Gls\GlsPoland\Soap\Engine\Metadata\Collection\XsdTypeCollection;
use Gls\GlsPoland\Soap\Engine\Metadata\Model\Property;
use Gls\GlsPoland\Soap\Engine\Metadata\Model\Type;
use Gls\GlsPoland\Soap\Engine\Metadata\Model\XsdType;
use SoapClient;

final class TypesParser
{
    /**
     * @var XsdTypeCollection
     */
    private $xsdTypes;

    public function __construct(XsdTypeCollection $xsdTypes)
    {
        $this->xsdTypes = $xsdTypes;
    }

    public function parse(SoapClient $client): TypeCollection
    {
        $collected = [];
        $soapTypes = (array) $client->__getTypes();
        foreach ($soapTypes as $soapType) {
            $properties = [];
            $lines = explode("\n", $soapType);
            if (!preg_match('/struct (?P<typeName>.*) {/', $lines[0], $matches)) {
                continue;
            }
            $xsdType = XsdType::create($matches['typeName']);

            foreach (array_slice($lines, 1) as $line) {
                if ($line === '}') {
                    continue;
                }
                preg_match('/\s* (?P<propertyType>.*) (?P<propertyName>.*);/', $line, $matches);
                $properties[] = new Property(
                    $matches['propertyName'],
                    $this->xsdTypes->getByNameWithFallback($matches['propertyType'])
                );
            }

            $collected[] = new Type($xsdType, new PropertyCollection(...$properties));
        }

        return new TypeCollection(...$collected);
    }
}
