<?php

namespace App\Commands;

use Illuminate\Console\Scheduling\Schedule;
use LaravelZero\Framework\Commands\Command;
use Illuminate\Support\Facades\File;

use App\Facades\Install;
use App\Facades\NginxVhost;
use App\Facades\NginxVhostFactory;
use App\Facades\TerminalHelper;
use App\Facades\Menus\StylesFactory;

use App\Helpers\NginxTemplateHelper;
use App\Menus\Nginx\NginxVhostGoBackAction;

use App\BladeFile;

use PhpSchool\CliMenu\Builder\CliMenuBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuItem\CheckboxItem;
use PhpSchool\CliMenu\Style\SelectableStyle;
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;

use Respect\Validation\Validator as v;
use Respect\Validation\Exceptions\NestedValidationException;

use Log;
use Closure;

/**
 *  Add and Edit Configurations of Vhosts from Nginx
 *
 *  Using php-school/cli-menu
 *
 *
 *
 */
class NginxVhostsCommand extends Command
{
    // path templates
    const TEMPLATES_DIR = '/resources/nginx/templates';

    // index for vhosts
    const VHOST_INDEX = 0;

    /**
     * The signature of the command.
     *
     * @var string
     */
    protected $signature = 'nginx:vhosts';

    /**
     * The description of the command.
     *
     * @var string
     */
    protected $description = 'Create and Manage Nginx Vhosts';

    /**
     *
     *
     *
     */
    private function selectTemplate()
    {
        $menu = function(CliMenuBuilder $builder)
        {
            // create blade
            $bladeFile = new BladeFile(self::TEMPLATES_DIR);

            $builder
                ->setTitle('Nginx > Add')
                ->setGoBackButtonText('Back');

            $nginxTemplateHelper = new NginxTemplateHelper();

            foreach($nginxTemplateHelper->find() as $template) {
                $submenuCallable = $this->createConfiguration($template, $bladeFile);
                $builder
                    ->addSubMenu($template['name'], $submenuCallable);
            }

            $builder->addLineBreak('-');
        };

        return $menu;
    }

    /**
     *  create Configuration, add for each template a submenu
     *
     *
     *  @param  array $template
     *  @param  Blade $blade
     *  @return CliMenuBuilder
     */
    private function createConfiguration($template, $bladeFile)
    {
        $menu = function(CliMenuBuilder $builder) use ($template, $bladeFile)
        {
            $configuration = [
                'domain' => '',
                'root' => '',
                'index' => 'index.php',
                'ssl' => true,
                'redirect_www' => true
            ];

            exec('find /lib/systemd/system/ -name "php[0-9\.]*-fpm.service"', $files);

            // create checkbox for ssl
            $checkboxSSL = new CheckboxItem('ssl', function(CliMenu $menu) use (&$configuration) {
                $configuration['ssl'] = $menu->getSelectedItem()->getChecked();
            });

            $checkboxSSL->setChecked($configuration['ssl']);

            // create checkbox for redirect from www
            $checkboxRedirect = new CheckboxItem('redirect www', function(CliMenu $menu) use (&$configuration) {
                $configuration['redirect_www'] = $menu->getSelectedItem()->getChecked();
            });

            $checkboxRedirect->setChecked($configuration['redirect_www']);

            $builder
                ->setTitle('Nginx > Add > '.$template['name'])
                ->setGoBackButtonText('Cancel')

                // input domain
                ->addItem('domain: -', function(CliMenu $menu) use (&$configuration) {

                    $input = $menu->askText();

                    if ($configuration['domain']) {
                        $input->setPlaceholderText($configuration['domain']);
                    }

                    $result = $input->ask();
                    $configuration['domain'] = $result->fetch();

                    $menu->getSelectedItem()->setText('domain: '.$result->fetch());
                    $menu->redraw();
                })

                // input root
                ->addItem('root: -', function(CliMenu $menu) use (&$configuration) {

                    $input = $menu->askText();

                    if ($configuration['root']) {
                        $input->setPlaceholderText($configuration['root']);
                    }

                    $result = $input->ask();
                    $configuration['root'] = $result->fetch();

                    $menu->getSelectedItem()->setText('root: '.$result->fetch());
                    $menu->redraw();
                })

                // input index
                ->addItem('index: '.$configuration['index'], function(CliMenu $menu) use (&$configuration) {

                    $input = $menu->askText();

                    if ($configuration['index']) {
                        $input->setPlaceholderText($configuration['index']);
                    }

                    $result = $input->ask();
                    $configuration['index'] = $result->fetch();

                    $menu->getSelectedItem()->setText('index: '.$result->fetch());
                    $menu->redraw();
                })
                ->addLineBreak('-');

            foreach($files as $index => $file) {
                $file = str_replace('/lib/systemd/system/', '', $file);
                $file = str_replace('.service', '', $file);

                $builder->addRadioItem($file, function(CliMenu $menu) use (&$configuration) {
                    $configuration['phpFpm'] = $menu->getSelectedItem()->getText();
                });
            }

            $builder
                ->addLineBreak('-')

                // options
                ->addMenuItem($checkboxSSL)
                ->addMenuItem($checkboxRedirect)
                ->addLineBreak('-')

                // create
                ->addItem('Create', function(CliMenu $menu) use (&$configuration, $template, $bladeFile) {

                    $data = $configuration;

                    // add directory for validator to check if file exits
                    $data['index'] = $data['root'].'/'.$data['index'];

                    $validator = v::key('domain', v::domain(false))
                        ->key('root', v::directory())
                        ->key('index', v::file())
                        ->key('phpFpm', v::notEmpty());

                    try {
                        $validator->assert($data);
                    } catch(NestedValidationException $exception) {
                        $errors = $exception->getMessages();
                    }

                    if (isset($errors)) {
                        TerminalHelper::confirmArray($menu, $errors);
                    } else {

                        // create filename
                        $filename = $configuration['domain'].'.conf';

                        // write configuration to file
                        $bladeFile->put($template['name'], '/etc/nginx/sites-available/'.$filename, $configuration);
                        $menu->confirm('Success!')->display('Ok!');

                        // invoke action
                        $action = new NginxVhostGoBackAction();
                        is_callable($action($menu));
                    }
                })
                ->addLineBreak('-');
        };

        return $menu;
    }

    /**
     *  let it rain
     *
     *
     */
    public function handle()
    {
        $submenuSelectTemplate = $this->selectTemplate();

        // create menu
        $builder = $this->menu('Nginx')

            // add Submenu for select templates
            ->addLineBreak('-')
            ->addSubMenu('Add', $submenuSelectTemplate);

        $builder->addLineBreak('-');

        // apperance
        $builder = StylesFactory::setMenuStyles($builder);

        $mainmenu = $builder->build();

        // remove first item
        $items = $mainmenu->getItems();
        unset($items[0]);
        $mainmenu->setItems($items);

        // adding current vhosts
        $mainmenu = NginxVhostFactory::addVhosts($mainmenu, NginxVhost::find(), self::VHOST_INDEX);
        $mainmenu->open();
    }
}