<?php

namespace A17\Blast\Commands;

use Illuminate\Console\Command;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use A17\Blast\Traits\Helpers;
use A17\Blast\Traits\TailwindViewports;

class Publish extends Command
{

    use Helpers;
    use TailwindViewports;

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'blast:publish
                                        {--install : Force install dependencies}
                                        {--url= : set the server url used to load the stories}
                                        {--o|output-dir=storybook-static : Directory where to store built files}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Build Static Storybook Instance.';

    /**
     * @var Filesystem
     */
    protected $filesystem;

    /**
     * @var mixed
     */
    private $storybookViewports;

    /**
     * @var mixed
     */
    private $storybookGlobalTypes;

    /**
     * @var mixed
     */
    private $storybookSortOrder;

    /**
     * @var mixed
     */
    private $expandedControls;

    /**
     * @var mixed
     */
    private $docsTheme;

    /**
     * @var mixed
     */
    private $customTheme;

    /**
     * @var mixed
     */
    private $storybookTheme;

    /**
     * @var mixed
     */
    private $storybookStatuses;

    /**
     * @var string
     */
    private $vendorPath;

    /**
     * @var mixed
     */
    private $storybookServer;

    /**
     * @param Filesystem $filesystem
     */
    public function __construct(Filesystem $filesystem)
    {
        parent::__construct();

        $this->filesystem = $filesystem;
        $this->storybookServer = config('blast.storybook_server_url');
        $this->vendorPath = $this->getVendorPath();
        $this->storybookStatuses = config('blast.storybook_statuses');
        $this->storybookTheme = config('blast.storybook_theme', false);
        $this->customTheme = config('blast.storybook_custom_theme', false);
        $this->docsTheme = config('blast.storybook_docs_theme', 'normal');
        $this->expandedControls = config('blast.storybook_expanded_controls');
        $this->storybookSortOrder = config('blast.storybook_sort_order', []);
        $this->storybookGlobalTypes = config(
            'blast.storybook_global_types',
            [],
        );
        $this->storybookViewports = config('blast.storybook_viewports', false);
    }

    /*
     * Executes the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $serverUrl = $this->option('url', $this->storybookServer);
        $npmInstall = $this->option('install');
        $installMessage = $this->getInstallMessage($npmInstall);
        $outputDir = $this->option('output-dir');

        if (Str::startsWith($outputDir, '/')) {
            $outputDir = Str::after($outputDir, '/');
        }

        $progressBar = $this->output->createProgressBar(3);
        $progressBar->setFormat('%current%/%max% [%bar%] %message%');

        $progressBar->setMessage($installMessage);
        $progressBar->start();

        // remove cors check file
        $cors_file_path = $this->vendorPath . '/tmp/_blast';
        if ($this->filesystem->exists($cors_file_path)) {
            $this->filesystem->delete($cors_file_path);
        }

        if ($npmInstall) {
            $this->newLine();
        }

        // install
        $this->installDependencies($npmInstall);

        usleep(250000);

        $this->info('');
        $progressBar->setMessage('Generating Stories...');
        $progressBar->advance();

        $generatedDocs = $this->callSilently('blast:generate-docs', [
            '--update-data' => 1,
        ]);

        if (!$generatedDocs) {
            $this->call('blast:generate-stories');
        }

        $this->info('');
        $progressBar->setMessage('Starting static Storybook build...');
        $progressBar->advance();

        $process = ['npm', 'run', 'build-storybook'];

        if ($outputDir) {
            $process[] = '--';

            $process = array_merge($process, [
                '-c',
                $this->filesystem->exists(base_path('.storybook'))
                    ? base_path('.storybook')
                    : '.storybook',
                '-o',
                $outputDir,
            ]);
        }

        $this->runProcessInBlast($process, true, [
            'STORYBOOK_SERVER_URL' => $serverUrl ?? $this->storybookServer,
            'STORYBOOK_STATIC_PATH' => public_path(),
            'STORYBOOK_PORT' => 6006,
            'STORYBOOK_STATUSES' => json_encode($this->storybookStatuses),
            'STORYBOOK_THEME' => json_encode($this->storybookTheme),
            'STORYBOOK_CUSTOM_THEME' => json_encode($this->customTheme),
            'STORYBOOK_DOCS_THEME' => json_encode($this->docsTheme),
            'STORYBOOK_EXPANDED_CONTROLS' => json_encode(
                $this->expandedControls,
            ),
            'STORYBOOK_GLOBAL_TYPES' => json_encode(
                $this->storybookGlobalTypes,
            ),
            'STORYBOOK_SORT_ORDER' => json_encode($this->storybookSortOrder),
            'STORYBOOK_VIEWPORTS' => json_encode(
                $this->buildTailwindViewports($this->storybookViewports),
            ),
            'LIBSTORYPATH' => $this->vendorPath . '/stories',
            'PROJECTPATH' => base_path(),
            'COMPONENTPATH' => base_path('resources/views/stories'),
        ]);

        usleep(250000);

        $this->info('');
        $progressBar->setMessage(
            'Copying static build to `/public/' . $outputDir . '`..',
        );
        $progressBar->advance();

        $outputPath = $this->vendorPath . '/' . $outputDir;
        $destPath = public_path($outputDir);

        $this->CopyDirectory($outputPath, $destPath);

        $this->info('');
        $progressBar->setMessage('Publish Complete');
        $progressBar->finish();

        $this->newLine();

        $this->info('View at ' . url($outputDir . '/index.html'));
    }
}
