<?php

namespace Ignite\Core\Listeners\ThemeScaffolding;

use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class LegacyThemeScaffolder
{
    /**
     * The folder under which themes are located.
     *
     * @var string
     */
    protected $folder = 'themes';

    /**
     * Run the legacy scaffold strategy.
     *
     * @param  string $name
     * @param  string $parent
     * @param  string $path
     * @param  OutputInterface $output
     * @return void
     */
    public function scaffold(string $name, string $parent, string $path, OutputInterface $output): void
    {
        $base = 'default';

        $output->writeln("Copying files from the {$base} theme...");
        $this->copyDefaultFiles($name, $base);

        $output->writeln('Customizing your theme...');
        $this->customizeTheme($name, $base);
        $this->updatePublicPath($name, $path);
    }

    /**
     * Copy the files from the default theme.
     *
     * @param  string $name
     * @param  string $base
     * @return void
     */
    protected function copyDefaultFiles(string $name, string $base = 'default'): void
    {
        $folder = ($base === 'default') ? 'vendor/ignite/themes' : null;
        $cwd = base_path();
        $commands = [
            Process::fromShellCommandline(sprintf('mkdir -p %s', $this->getPath($name, 'src/js/')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'src/js/*', $folder), $this->getPath($name, 'src/js/')), $cwd),
            Process::fromShellCommandline(sprintf('mkdir -p %s', $this->getPath($name, 'src/scss/')), $cwd),
            Process::fromShellCommandline(sprintf('cp %s %s', $this->getPath($base, 'src/scss/style.scss', $folder), $this->getPath($name, 'src/scss/')), $cwd),
            Process::fromShellCommandline(sprintf('cp %s %s', $this->getPath($base, 'src/scss/_variables.scss', $folder), $this->getPath($name, 'src/scss/')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'dist/fonts', $folder), $this->getPath($name, 'dist/fonts')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'dist/images', $folder), $this->getPath($name, 'dist/images')), $cwd),
            Process::fromShellCommandline(sprintf('mkdir -p %s', $this->getPath($name, 'dist/stylesheets')), $cwd),
            Process::fromShellCommandline(sprintf('mkdir -p %s', $this->getPath($name, 'dist/javascripts')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, '.babelrc', $folder), $this->getPath($name, '.babelrc')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, '.gitignore', $folder), $this->getPath($name, '.gitignore')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'webpack.mix.js', $folder), $this->getPath($name, 'webpack.mix.js')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'gulpfile.js', $folder), $this->getPath($name, 'gulpfile.js')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'package.json', $folder), $this->getPath($name, 'package.json')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'yarn.lock', $folder), $this->getPath($name, 'yarn.lock')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'readme.md', $folder), $this->getPath($name, 'readme.md')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'views/cms', $folder), $this->getPath($name, 'views/cms')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'forms', $folder), $this->getPath($name, 'forms')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'dist/javascripts/conditionals.js', $folder), $this->getPath($name, 'dist/javascripts/conditionals.js')), $cwd),
            Process::fromShellCommandline(sprintf('cp -r %s %s', $this->getPath($base, 'dashboards', $folder), $this->getPath($name, 'dashboards')), $cwd),
        ];

        foreach ($commands as $command) {
            $command->run();

            if (! $command->isSuccessful()) {
                throw new ProcessFailedException($command);
            }
        }
    }

    /**
     * Customize the theme files.
     *
     * @param  string $name
     * @param  string $base
     * @return void
     */
    protected function customizeTheme(string $name, string $base = 'default'): void
    {
        $base = ucfirst(strtolower($base));
        $title = ucfirst(strtolower($name));
        $cwd = base_path();

        $commands = [
            Process::fromShellCommandline(sprintf('sed -i "1s/%s/%s/" %s', $base, $title, $this->getPath($name, 'readme.md')), $cwd),
            Process::fromShellCommandline(sprintf('sed -i "39s/\/\///" %s', $this->getPath($name, 'gulpfile.js')), $cwd),
        ];

        foreach ($commands as $command) {
            $command->run();

            if (! $command->isSuccessful()) {
                throw new ProcessFailedException($command);
            }
        }
    }

    /**
     * Update the public path in the webpack.mix.js file and create the public theme folder.
     *
     * @param  string $name
     * @param  string $path
     * @return self
     */
    protected function updatePublicPath(string $name, string $path)
    {
        $webpackMixPath = $path . DIRECTORY_SEPARATOR . 'webpack.mix.js';
        $webpackMixContents = file_get_contents($webpackMixPath);

        $webpackMixContents = str_replace(
            'const realPublicPath = \'\';',
            'const realPublicPath = \'../../public/themes/' . $name . '/\';',
            $webpackMixContents
        );
        file_put_contents($webpackMixPath, $webpackMixContents);

        $themeFolder = public_path('themes/' . $name);
        if (! is_dir($themeFolder)) {
            mkdir($themeFolder, 0755, true);
        }

        return $this;
    }

    /**
     * Get the path to a directory in context of the current theme.
     *
     * @param  string $name
     * @param  string|null $path
     * @param  string|null $folder
     * @return string
     */
    protected function getPath(string $name, ?string $path = null, ?string $folder = null): string
    {
        $folder = is_null($folder) ? $this->folder : $folder;

        return base_path(
            $folder . DIRECTORY_SEPARATOR .
            $name .
            (is_null($path) ? '' : DIRECTORY_SEPARATOR . $this->normalizePath($path))
        );
    }

    /**
     * Normalize the path for use across different OSs.
     *
     * @param  string $path
     * @return string
     */
    protected function normalizePath(string $path): string
    {
        return str_replace('/', DIRECTORY_SEPARATOR, $path);
    }
}
