#!/usr/local/bin/php
<?php

use Symfony\Component\Yaml\Yaml;

define('ROOT', dirname(__DIR__));

require ROOT . '/vendor/autoload.php';

const types = [
    'blob'         => '',
    'bool'         => 'bool',
    'char'         => 'string',
    'datetime'     => '\DateTimeInterface',
    'timestamp'    => '\DateTimeInterface',
    'html'         => 'string',
    'int'          => 'int',
    'numeric'      => 'float',
    'serial'       => 'int',
    'text'         => 'string',
    'varchar'      => 'string',
    'phone_number' => 'PhoneNumber',
];

$files = array_merge(glob(ROOT . '/src/Entity/*.php'),
                     array_merge(glob(ROOT . '/components/*/Entity/*.php'),
                                 glob(ROOT . '/plugins/*/Entity/*.php')));

$classes = [];

foreach ($files as $file) {

    require_once $file;

    $declared = get_declared_classes();
    foreach ($declared as $dc) {
        if (preg_match('/(App|(Component|Plugin)\\\\[^\\\\]+)\\\\Entity/', $dc) && !in_array($dc, $classes)) {
            $class = $dc;
            $classes[] = $class;
            break;
        }
    }

    $no_ns_class  = preg_replace('/.*?\\\\/', '', $class);
    $schema       = $class::schemaDef();
    $fields       = array_keys($schema['fields']);
    $fields_code  = [];
    $methods_code = [];
    foreach ($fields as $field) {
        $nullable       = !@$schema['fields'][$field]['not null'] ? '?' : '';
        $type           = types[$schema['fields'][$field]['type']];
        $type           = $type !== '' ? $nullable . $type : $type;
        $method_name    = str_replace([' ', 'Gsactor'], ['', 'GSActor'], ucwords(str_replace('_', ' ', $field)));
        $default        = @$schema['fields'][$field]['default'];

        if (isset($default) && $nullable != '?' && $type != '\DateTimeInterface') {
            if (is_string($default)) {
                $default = "'{$default}'";
            } elseif ($type == 'bool') {
                $default = $default ? 'true' : 'false';
            }

            $fields_code[]  = "    private {$type} \${$field} = {$default};";
        } else {
            $fields_code[]  = "    private {$type} \${$field};";
        }

        $methods_code[] = "    public function set{$method_name}({$type} \${$field}): self" .
                        "\n    {\n        \$this->{$field} = \${$field};\n        return \$this;\n    }" . "\n\n" .
                        "    public function get{$method_name}()" . ($type !== '' ? ": {$type}" : '') .
                        "\n    {\n        return \$this->{$field};\n    }" . "\n";
    }

    $fields_code  = implode("\n", $fields_code);
    $methods_code = implode("\n", $methods_code) . "\n";

    $begin = '// {{{ Autocode';
    $end   = '// }}} Autocode';
    $code  = "
    {$begin}
    // @codeCoverageIgnoreStart
{$fields_code}

{$methods_code}
    // @codeCoverageIgnoreEnd
    {$end}";

    foreach (['/\\//' => '\\/', '/ /' => '\\ '] as $from => $to) {
        $begin = preg_replace($from, $to, $begin);
        $end   = preg_replace($from, $to, $end);
    }

    $in_file  = file_get_contents($file);
    $out_file = preg_replace("/\\s*{$begin}[^\\/]*{$end}/m", $code, $in_file);

    file_put_contents($file, $out_file);
}