<?php

namespace App\Http\Middleware;

use App\Configuration;
use App\DataMigration;
use App\Facade\UserConfig;
use App\Helpers\MiscHelper;
use Closure;
use Illuminate\Foundation\Application;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;

class AppInstallation
{
    private $baseDirectory;
    private $environmentFilePath;

    /**
     * The application instance.
     *
     * @var \Illuminate\Foundation\Application
     */
    protected $app;

    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Foundation\Application  $app
     * @return void
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->baseDirectory = dirname(dirname(dirname(__DIR__)));
        $this->environmentFilePath = sprintf('%s/.env', $this->baseDirectory);
    }

    public function handle(Request $request, Closure $next)
    {
        // We always need an encryption key if not already present
        $this->generateAppKey();

        if ($this->app->runningInConsole())
        {
            // Allow the console to run successfully even if we're not installed
            return $next($request);
        }

        // See if the successful flag has been written to the .env file
        $isAppInstalled = MiscHelper::getEnvironmentSetting('APP_INSTALLED');

        if ($request->is('install/*'))
        {
            // Already in the installer
            // For security reasons, don't allow the installer to be used if it has been previously completed
            if (boolval($isAppInstalled))
            {
                return redirect(route('home'));
            }

            return $next($request);
        }

        if ($isAppInstalled)
        {
            // See if an update is necessary
            $this->updateDatabaseIfRequired();

            // App is configured, continue on
            return $next($request);
        }

        return redirect(route('install.check'));
    }

    private function generateAppKey()
    {
        // Generate an application key and store to the .env file
        if (!file_exists($this->environmentFilePath))
        {
            $key = MiscHelper::randomString(32);
            file_put_contents($this->environmentFilePath, sprintf('APP_KEY=%s', $key) . PHP_EOL);
            app('config')->set(['app' => ['key' => $key]]);
        }
    }

    private function updateDatabaseIfRequired()
    {
        $versionNumber = UserConfig::getOrCreateModel('app_version');
        $appVersionNumber = config('app.version');

        if (is_null($appVersionNumber) || $versionNumber->value != $appVersionNumber)
        {
            Log::info('Upgrading database', ['new_version' => $appVersionNumber]);

            Artisan::call('cache:clear');
            Artisan::call('migrate', ['--force' => true]);

            Artisan::call('db:seed');

            $className = sprintf('DataMigrationV%s', str_replace(['.', '-'], '_', $appVersionNumber));
            if (class_exists($className))
            {
                /** @var DataMigration $upgradeClass */
                $upgradeClass = new $className;
                $upgradeClass->run($versionNumber);
            }
        }

        $versionNumber->value = $appVersionNumber;
        $versionNumber->save();
    }
}