<commit_before><?php
declare(strict_types=1);

namespace WyriHaximus\ApiClient\Tools;

use Doctrine\Common\Inflector\Inflector;
use League\CLImate\CLImate;
use PhpParser\Builder\Method;
use PhpParser\Builder\Property;
use PhpParser\BuilderFactory;
use PhpParser\PrettyPrinter;
use PhpParser\Node;
use Symfony\Component\Yaml\Yaml;

class ResourceGenerator
{
    protected $climate;

    public function __construct(CLImate $climate)
    {
        $this->climate = $climate;

        $this->setUpArguments();
    }

    protected function setUpArguments()
    {
        $this->climate->arguments->add([
            'definition' => [
                'description' => 'YAML definition file',
                'required'    => true,
            ],
            'path' => [
                'description' => 'Path to the resource directory',
                'required'    => true,
            ],
            'sync' => [
                'prefix'       => 's',
                'longPrefix'   => 'sync',
                'defaultValue' => true,
                'noValue'      => false,
                'description'  => 'Don\'t generate Sync resource',
                'castTo'       => 'bool',
            ],
            'async' => [
                'prefix'       => 'as',
                'longPrefix'   => 'async',
                'defaultValue' => true,
                'noValue'      => false,
                'description'  => 'Don\'t generate Async resource',
                'castTo'       => 'bool',
            ],
        ]);
    }

    public function run()
    {
        $yaml = $this->readYaml($this->climate->arguments->get('definition'));
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createBaseClass($yaml)
        );
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . 'Async' . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createExtendingClass('Async', $yaml)
        );
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . 'Sync' . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createExtendingClass('Sync', $yaml)
        );
    }

    protected function readYaml(string $filename): array
    {
        return Yaml::parse(file_get_contents($filename));
    }

    protected function createBaseClass(array $yaml)
    {
        $factory = new BuilderFactory;

        $class = $factory->class($yaml['class'])
            ->implement('ResourceInterface')
            ->makeAbstract();
        $class->addStmt(
            new Node\Stmt\TraitUse([
                new Node\Name('TransportAwareTrait')
            ])
        );

        foreach ($yaml['properties'] as $name => $details) {
            $type = $details;
            if (is_array($details)) {
                $type = $details['type'];
            }
            $class->addStmt($this->createProperty($factory, $type, $name, $details));
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
        }

        $node = $factory->namespace($yaml['namespace'])
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\ResourceInterface'))
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\TransportAwareTrait'))
            ->addStmt($class)

            ->getNode()
        ;

        $prettyPrinter = new PrettyPrinter\Standard();
        return $prettyPrinter->prettyPrintFile([
            $node
        ]) . PHP_EOL;
    }

    protected function createProperty(BuilderFactory $factory, string $type, string $name, $details): Property<commit_msg>Generate resource interface<commit_after><?php
declare(strict_types=1);

namespace WyriHaximus\ApiClient\Tools;

use Doctrine\Common\Inflector\Inflector;
use League\CLImate\CLImate;
use PhpParser\Builder\Method;
use PhpParser\Builder\Property;
use PhpParser\BuilderFactory;
use PhpParser\PrettyPrinter;
use PhpParser\Node;
use Symfony\Component\Yaml\Yaml;

class ResourceGenerator
{
    protected $climate;

    public function __construct(CLImate $climate)
    {
        $this->climate = $climate;

        $this->setUpArguments();
    }

    protected function setUpArguments()
    {
        $this->climate->arguments->add([
            'definition' => [
                'description' => 'YAML definition file',
                'required'    => true,
            ],
            'path' => [
                'description' => 'Path to the resource directory',
                'required'    => true,
            ],
            'sync' => [
                'prefix'       => 's',
                'longPrefix'   => 'sync',
                'defaultValue' => true,
                'noValue'      => false,
                'description'  => 'Don\'t generate Sync resource',
                'castTo'       => 'bool',
            ],
            'async' => [
                'prefix'       => 'as',
                'longPrefix'   => 'async',
                'defaultValue' => true,
                'noValue'      => false,
                'description'  => 'Don\'t generate Async resource',
                'castTo'       => 'bool',
            ],
        ]);
    }

    public function run()
    {
        $yaml = $this->readYaml($this->climate->arguments->get('definition'));
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createBaseClass($yaml)
        );
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . $yaml['class'] . 'Interface.php',
            $this->createInterface($yaml)
        );
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . 'Async' . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createExtendingClass('Async', $yaml)
        );
        file_put_contents(
            $this->climate->arguments->get('path') . DIRECTORY_SEPARATOR . 'Sync' . DIRECTORY_SEPARATOR . $yaml['class'] . '.php',
            $this->createExtendingClass('Sync', $yaml)
        );
    }

    protected function readYaml(string $filename): array
    {
        return Yaml::parse(file_get_contents($filename));
    }

    protected function createBaseClass(array $yaml)
    {
        $factory = new BuilderFactory;

        $class = $factory->class($yaml['class'])
            ->implement($yaml['class'] . 'Interface')
            ->makeAbstract();
        $class->addStmt(
            new Node\Stmt\TraitUse([
                new Node\Name('TransportAwareTrait')
            ])
        );

        foreach ($yaml['properties'] as $name => $details) {
            $type = $details;
            if (is_array($details)) {
                $type = $details['type'];
            }
            $class->addStmt($this->createProperty($factory, $type, $name, $details));
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
        }

        $node = $factory->namespace($yaml['namespace'])
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\TransportAwareTrait'))
            ->addStmt($class)

            ->getNode()
        ;

        $prettyPrinter = new PrettyPrinter\Standard();
        return $prettyPrinter->prettyPrintFile([
            $node
        ]) . PHP_EOL;
    }

    protected function createInterface(array $yaml)
    {
        $factory = new BuilderFactory;

        $class = $factory->interface($yaml['class'] . 'Interface')
            ->extend('ResourceInterface');

        foreach ($yaml['properties'] as $name => $details) {
            $type = $details;
            if (is_array($details)) {
                $type = $details['type'];
            }
            $class->addStmt($this->createMethod($factory, $type, $name, $details));
        }

        $node = $factory->namespace($yaml['namespace'])
            ->addStmt($factory->use('WyriHaximus\ApiClient\Resource\ResourceInterface'))
            ->addStmt($class)
            ->getNode()
        ;

        $prettyPrinter = new PrettyPrinter\Standard();
        return $prettyPrinter->prettyPrintFile([
            $node
        ]) . PHP_EOL;
    }

    protected function createProperty(BuilderFactory $factory, string $type, string $name, $details): Property
{'fraction_non_alphanumeric': 0.14770696843359143, 'fraction_numerical': 0.00023823704586063132, 'mean_word_length': 1.9254355400696863, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 132, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1174642', 'n_tokens_mistral': 2386, 'n_tokens_neox': 2328, 'n_words': 399}