<?php

namespace Shm\ShmRPC\ShmRPCCodeGen\CodeGenPhp;

use Shm\ShmTypes\CompositeTypes\VizType\VizType;
use Shm\ShmTypes\EnumType;
use Shm\ShmTypes\StructureType;

class CreateClassByStructure
{

    private string $namespace = '';
    private string $dirFiles = '';
    private string $className = '';

    public function __construct(string $namespace, string $dirFiles, string $className)
    {
        $this->namespace = $namespace;
        $this->dirFiles = $dirFiles;
        $this->className = $className;
        //Создаем папку если не существует
        if (!is_dir($this->dirFiles)) {
            mkdir($this->dirFiles, 0777, true);
        }
    }

    public function create(StructureType $structure)
    {


        $class = new \Nette\PhpGenerator\ClassType($this->className);
        foreach ($structure->items as $key => $item) {


            if ($item->type === 'static') {
                continue;
            }

            // Если это viz — пропускаем (настройка аналитики, не поле данных)
            if ($item instanceof VizType) {
                continue;
            }

            if ($item->type === 'structure') {

                $structureClassName = $this->className . ucfirst($key);
                $createClassByStructure = new CreateClassByStructure($this->namespace, $this->dirFiles, $structureClassName);
                $createClassByStructure->create($item);

                $class->addProperty($key)->setType($structureClassName);

                $method = $class->addMethod($key);
                $method->setReturnType($structureClassName);
                //static
                $method->setStatic();
                $method->setBody('return new ' . $structureClassName . '();');

                $method = $class->addMethod('set' . ucfirst($key))
                    ->setReturnType('self');
                $method->addParameter('value')->setType($structureClassName);
                $method->setBody('$this->' . $key . ' = $value; return $this;');
            } else {
                $class->addProperty($key);

                $method = $class->addMethod('set' . ucfirst($key));
                $method->setReturnType('self');

                $type = $item->type;
                $type = TypeToPhp::convert($type);
                if ($item instanceof EnumType) {

                    $createEnum = new CreateEnum($this->namespace, $this->dirFiles, $item->key . 'Enum');
                    $type = $createEnum->create($item);
                }

                $method->addParameter('value')->setType($type);
                $method->setBody('$this->' . $key . ' = $value; return $this;');
            }
        }

        //Добаляем функцию которая возвращает все значения в виде массива ключ => значение
        $method = $class->addMethod('data');
        $method->setReturnType('array');

        $dataBody = [];
        foreach ($structure->items as $key => $item) {

            if ($item instanceof VizType) {
                continue;
            }

            if ($item->type === 'structure') {

                //Проверяем есть ли данные в свойстве и только тогда возвращаеь data если нет то не возвращаем

                $dataBody[] = "if(isset(\$this->$key)){
                    \$data['$key'] = \$this->" . $key . "->data();
                }";
            } else {
                $dataBody[] =  "if(isset(\$this->$key)){
                    \$data['$key'] = \$this->$key;
                }";
            }
        }



        $method->setBody('$data = []; ' . implode(' ', $dataBody) . ' return $data;');

        $output = "<?php\n\n"; // заголовок файла
        $output .= "namespace " . $this->namespace . ";\n";

        $output .= $class . "\n\n"; // собираем все классы

        $filePath = $this->dirFiles . $this->className . '.php';
        file_put_contents($filePath, $output);
    }
}