<?php

namespace App\Http\Controllers;

use App\Configuration;
use App\Facade\UserConfig;
use App\Helpers\MiscHelper;
use App\Http\Requests\StoreUserRequest;
use App\Storage;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;

class InstallController extends Controller
{
    public function administrator(StoreUserRequest $request)
    {
        // Validate we're at the required stage
        $stage = 3;
        if (intval($request->session()->get('install_stage')) < $stage)
        {
            return redirect(route('install.check'));
        }

        // If we already have an admin account, this step can be skipped
        $canSkip = User::where('is_admin', true)->count() > 0;
        
        if ($canSkip && $request->has('skip'))
        {
            return $this->completeSetup();
        }

        if ($request->method() == 'POST')
        {
            $user = new User();
            $user->name = $request->get('name');
            $user->email = $request->get('email');
            $user->password = bcrypt($request->get('password'));
            $user->is_admin = true;
            $user->is_activated = true;
            $user->save();

            return $this->completeSetup();
        }

        return view('install.administrator', [
            'can_skip' => $canSkip
        ]);
    }

    public function check(Request $request)
    {
        // This is the first installation step therefore it doesn't need to verify the stage

        if ($request->getMethod() == 'POST')
        {
            $request->session()->put('install_stage', 2);
            return redirect(route('install.database'));
        }

        $canContinue = true;
        $runtimeMinimum = '7.0.0'; // this minimum is imposed by Laravel 5.5
        $runtimeVersion = phpversion();
        $phpIsValid = version_compare($runtimeVersion, $runtimeMinimum) >= 0;

        if (!$phpIsValid)
        {
            $canContinue = false;
        }

        $requiredModules = [
            'curl' => 'installer.php_modules.curl',
            'pdo_mysql' => 'installer.php_modules.mysql',
            'gd' => 'installer.php_modules.gd'
        ];
        $availableModules = [];

        foreach ($requiredModules as $key => $langString)
        {
            $availableModules[$key] = extension_loaded($key);
            if (!$availableModules[$key])
            {
                $canContinue = false;
            }
        }

        $uploadLimit = MiscHelper::convertToBytes(ini_get('upload_max_filesize'));
        $postMaxSize = MiscHelper::convertToBytes(ini_get('post_max_size'));

        $recommendedMinimum = 4 * 1024 * 1024;

        return view('install.check', [
            'available_modules' => $availableModules,
            'can_continue' => $canContinue,
            'php_is_valid' => $phpIsValid,
            'php_version_current' => $runtimeVersion,
            'php_version_required' => $runtimeMinimum,
            'post_max_size' => ($postMaxSize / 1024 / 1024),
            'post_max_size_warning' => $postMaxSize < $recommendedMinimum,
            'recommended_minimum_upload' => ($recommendedMinimum / 1024 / 1024),
            'upload_limit' => ($uploadLimit / 1024 / 1024),
            'upload_limit_warning' => $uploadLimit < $recommendedMinimum,
            'required_modules' => $requiredModules
        ]);
    }

    public function database(Request $request)
    {
        // Validate we're at the required stage
        $stage = 2;
        if (intval($request->session()->get('install_stage')) < $stage)
        {
            return redirect(route('install.check'));
        }

        if ($request->method() == 'POST')
        {
            $baseDirectory = dirname(dirname(dirname(__DIR__)));

            $data = [
                sprintf('APP_KEY=%s', config('app.key')),
                'DB_CONNECTION=mysql',
                sprintf('DB_HOST=%s', $request->get('mysql-server')),
                sprintf('DB_PORT=%s', intval($request->get('mysql-port'))),
                sprintf('DB_DATABASE=%s', $request->get('mysql-database')),
                sprintf('DB_USERNAME=%s', $request->get('mysql-username')),
                sprintf('DB_PASSWORD=%s', $request->get('mysql-password'))
            ];
            file_put_contents(sprintf('%s/.env', $baseDirectory), join(PHP_EOL, $data) . PHP_EOL);

            // Update the in-memory configuration ready for Artisan :)
            $configData = [
                'connections' => [
                    'mysql' => [
                        'driver' => 'mysql',
                        'host' => $request->get('mysql-server'),
                        'port' => intval($request->get('mysql-port')),
                        'database' => $request->get('mysql-database'),
                        'username' => $request->get('mysql-username'),
                        'password' => $request->get('mysql-password')
                    ]
                ]
            ];
            config(['database' => array_replace_recursive(config('database'), $configData)]);

            try
            {
                DB::reconnect();

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

                $versionNumber = UserConfig::getOrCreateModel('app_version');
                $versionNumber->value = config('app.version');
                $versionNumber->save();

                $request->session()->put('install_stage', 3);
                return redirect(route('install.administrator'));
            }
            catch (\Exception $ex)
            {
                $request->session()->flash('database_error', $ex->getMessage());
                return redirect(route('install.database'))
                    ->withInput($request->input());
            }
        }

        return view('install.database', [
            'database_error' => $request->session()->get('database_error')
        ]);
    }

    private function completeSetup()
    {
        // Flag as installed
        MiscHelper::setEnvironmentSetting('APP_INSTALLED', true);

        // Switch to database sessions (more reliable)
        MiscHelper::setEnvironmentSetting('SESSION_DRIVER', 'database');

        // Add an internal storage if it doesn't already exist
        $this->createInternalStorageLocationIfNotExist();

        // Skip forward. If you go past Go, collect £200!
        return redirect(route('home', ['install_completed' => true]));
    }

    private function createInternalStorageLocationIfNotExist()
    {
        $storage = Storage::where('is_internal', true)->first();
        if (is_null($storage))
        {
            $location = sprintf('%s/storage/app/albums', dirname(dirname(dirname(__DIR__))));

            $storage = new Storage();
            $storage->name = trans('installer.default_storage_name');
            $storage->is_active = true;
            $storage->is_default = true;
            $storage->is_internal = true;
            $storage->location = $location;
            $storage->source = 'LocalFilesystemSource';
            $storage->save();

            // Try and create the physical location
            if (!file_exists($location))
            {
                @mkdir($location);
            }
        }
    }
}