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

/*
 * This file is part of php-restcord.
 *
 * (c) Aaron Scherer <aequasi@gmail.com>
 *
 * This source file is subject to the license that is bundled
 * with this source code in the file LICENSE
 */

function recursiveRemoveDirectory($directory)
{
    foreach (glob("{$directory}/*") as $file) {
        if (is_dir($file)) {
            recursiveRemoveDirectory($file);
        } else {
            unlink($file);
        }
    }
    rmdir($directory);
}

$path = __DIR__.'/../src/Interfaces';
try {
    recursiveRemoveDirectory($path);
} catch (\Exception $e) {
}
mkdir($path, 02775, true);
$path = realpath($path);

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

use gossi\codegen\generator\CodeGenerator;
use gossi\codegen\model\PhpInterface;
use gossi\codegen\model\PhpMethod;
use gossi\codegen\model\PhpParameter;
use gossi\codegen\model\PhpProperty;
use GuzzleHttp\Command\Result;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

$loader = new Twig_Loader_Filesystem(__DIR__.'/../src/Resources/');
$twig   = new Twig_Environment($loader, ['debug' => true]);
$twig->addExtension(new Twig_Extension_Debug());

$license = <<<EOF
<?php

/*
 * Copyright 2017 Aaron Scherer
 *
 * This source file is subject to the license that is bundled
 * with this source code in the file LICENSE
 *
 * @package     restcord/restcord
 * @copyright   Aaron Scherer 2017
 * @license     MIT
 */
\n
EOF;

/** @noinspection PhpUnhandledExceptionInspection */
(new Application('Build Dummy Classes', '1.0.0'))
    ->register('buildDummyClasses')
    ->addArgument('version', InputArgument::REQUIRED, 'Version to build')
    ->setCode(
        function (InputInterface $input, OutputInterface $output) use ($twig, $license, $path) {
            $style = new \Symfony\Component\Console\Style\SymfonyStyle($input, $output);
            $style->title("Building Dummy Classes for Gateway v".$input->getArgument('version'));

            $definition = \GuzzleHttp\json_decode(
                file_get_contents(
                    __DIR__.'/../src/Resources/service_description-v'.$input->getArgument('version').'.json'
                ),
                true
            );

            $generator = new CodeGenerator();
            foreach ($definition['operations'] as $resource => $operations) {
                $resource = str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $resource)));

                $class = new PhpInterface();
                $class->setQualifiedName('RestCord\\Interfaces\\'.ucwords($resource));
                $class->setDescription(ucwords($resource)." Intellisense Helper");
                $class->setMethods(
                    array_map(
                        function ($name, $operation) use ($class, $resource) {
                            $options = new PhpParameter('options');
                            $options->setType(
                                'array',
                                '['.implode(
                                    ', ',
                                    array_map(
                                        function ($name, $parameter) {
                                            return "'".$name."' => '".$parameter['type']."'";
                                        },
                                        array_keys($operation['parameters']),
                                        $operation['parameters']
                                    )
                                ).']'
                            );

                            $returnType = 'array';
                            if (isset($operation['responseTypes']) && sizeof($operation['responseTypes']) >= 1) {
                                $firstType = $operation['responseTypes'][0]['type'];
                                $array     = stripos($firstType, 'Array<') !== false;
                                if ($array) {
                                    $firstType = substr($firstType, 6, -1);
                                }

                                $temp = explode("/", $firstType);
                                $returnType = sprintf(
                                    "\\RestCord\\Model\\%s\\%s",
                                    str_replace(
                                        ' ',
                                        '',
                                        ucwords(str_replace('-', ' ', $temp[0]))
                                    ),
                                    str_replace(
                                        ' ',
                                        '',
                                        ucwords(str_replace('-', ' ', $temp[1]))
                                    )
                                );

                                $returnType = mapBadDocs($name, $operation, $returnType);

                                if (!class_exists($returnType)) {
                                    $returnType = "\\".Result::class;
                                }

                                $returnType .= $array ? '[]' : '';
                            }

                            $method = new PhpMethod(
                                lcfirst(str_replace(' ', '', ucwords(str_replace('-', ' ', $name))))
                            );
                            $method->setType($returnType, $operation['responseNote'] ?? '');
                            if (isset($operation['link'])) {
                                $method->setLongDescription('@see '.$operation['link']);
                            }
                            $method->setParameters([$options]);
                            $method->setVisibility('public');

                            return $method;
                        },
                        array_keys($operations),
                        $operations
                    )
                );

                file_put_contents($path.'/'.ucwords($resource).'.php', $license.$generator->generate($class));
            }

            $style->success('Finished. Classes built in: '.realpath($path));
        }
    )
    ->getApplication()
    ->setDefaultCommand('buildDummyClasses', true)
    ->run();

function mapBadDocs(string $name, array $operation, string $cls): string
{
    switch ($cls) {
        case '\RestCord\Model\User\DmChannel':
            $newCls = '\RestCord\Model\Channel\DmChannel';
            break;
        case '\RestCord\Model\Channel\Invite':
        case '\RestCord\Model\Guild\Invite':
            $newCls = '\RestCord\Model\Invite\Invite';
            break;
        case '\RestCord\Model\Guild\GuildChannel':
            $newCls = '\RestCord\Model\Channel\GuildChannel';
            break;
        case '\RestCord\Model\Guild\User':
        case '\RestCord\Model\Channel\User':
            $newCls = '\RestCord\Model\User\User';
            break;
        case 'ISO8601':
        case '\RestCord\Model\Channel\ISO8601':
            $newCls = '\DateTimeImmutable';
            break;
        default:
            return $cls;
    }

    trigger_error($name.' operation in '.$operation['resource'].' has a bad responseType: '.$cls);

    return $newCls;
}
