<?php

namespace App\Http\Controllers\Admin;

use App\Album;
use App\Configuration;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\Group;
use App\Helpers\ConfigHelper;
use App\Helpers\DbHelper;
use App\Helpers\MiscHelper;
use App\Helpers\PermissionsHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveSettingsRequest;
use App\Label;
use App\Mail\TestMailConfig;
use App\Photo;
use App\PhotoComment;
use App\Services\GiteaService;
use App\Services\GithubService;
use App\Services\PhotoService;
use App\Storage;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\View;

class DefaultController extends Controller
{
    private $passwordSettingKeys;

    public function __construct()
    {
        $this->middleware('auth');
        View::share('is_admin', true);

        $this->passwordSettingKeys = [
            'rabbitmq_password',
            'smtp_password',
            'facebook_app_secret',
            'google_app_secret',
            'twitter_app_secret'
        ];
    }

    public function about()
    {
        return Theme::render('admin.about', [
            'current_version' => config('app.version'),
            'licence_text' => file_get_contents(sprintf('%s/LICENSE', dirname(dirname(dirname(dirname(__DIR__))))))
        ]);
    }

    public function aboutLatestRelease()
    {
        try
        {
            $giteaService = new GiteaService();
            $releaseInfo = $giteaService->checkForLatestRelease();

            // Convert the publish date so we can re-format it with the user's settings
            $publishDate = \DateTime::createFromFormat('Y-m-d\TH:i:sP', $releaseInfo->published_at);

            // HTML-ify the body text
            $body = nl2br($releaseInfo->body);
            $body = preg_replace('/\*\*(.+)\*\*/', '<b>$1</b>', $body);

            // Remove the "v" from the release name
            $version = substr($releaseInfo->tag_name, 1);

            // Determine if we can upgrade
            $canUpgrade = version_compare($version, config('app.version')) > 0;

            return response()->json([
                'can_upgrade' => $canUpgrade,
                'body' => $body,
                'name' => $version,
                'publish_date' => $publishDate->format(UserConfig::get('date_format')),
                'url' => $releaseInfo->html_url
            ]);
        }
        catch (\Exception $ex)
        {
            return response()->json(['error' => $ex->getMessage()]);
        }
    }

    public function metadataUpgrade()
    {
        $albumIDs = DbHelper::getAlbumIDsForCurrentUser();

        $photoMetadata = DB::table('photos')
            ->whereIn('album_id', $albumIDs)
            ->select([
                'album_id',
                DB::raw('MIN(metadata_version) AS min_metadata_version')
            ])
            ->groupBy('album_id')
            ->get();

        $resultingAlbumIDs = [];
        foreach ($photoMetadata as $metadata)
        {
            if (isset($metadata->min_metadata_version) && $metadata->min_metadata_version > 0)
            {
                $resultingAlbumIDs[$metadata->album_id] = $metadata->min_metadata_version;
            }
        }

        // Now load the full album definitions
        $albumsQuery = DbHelper::getAlbumsForCurrentUser_NonPaged();
        $albumsQuery->whereIn('id', array_keys($resultingAlbumIDs));
        $albums = $albumsQuery->paginate(UserConfig::get('items_per_page'));

        /** @var Album $album */
        foreach ($resultingAlbumIDs as $albumID => $metadataMinVersion)
        {
            foreach ($albums as $album)
            {
                if ($album->id == $albumID)
                {
                    $album->min_metadata_version = $metadataMinVersion;
                }
            }
        }

        return Theme::render('admin.metadata_upgrade', [
            'albums' => $albums,
            'current_metadata_version' => PhotoService::METADATA_VERSION
        ]);
    }

    public function index()
    {
        $this->authorizeAccessToAdminPanel();

        $albumCount = count(DbHelper::getAlbumIDsForCurrentUser());
        $photoCount = Photo::all()->count();
        $groupCount = Group::all()->count();
        $labelCount = Label::all()->count();
        $commentCount = PhotoComment::whereNotNull('approved_at')->count();
        $userCount = User::where('is_activated', true)->count();

        $minMetadataVersion = Photo::min('metadata_version');
        $metadataUpgradeNeeded = $minMetadataVersion > 0 && $minMetadataVersion < PhotoService::METADATA_VERSION;

        // Default to a supported function call to get the OS version
        $osVersion = sprintf('%s %s', php_uname('s'), php_uname('r'));

        // If the exec() function is enabled, we can do a bit better
        if (MiscHelper::isExecEnabled())
        {
            $osVersion = exec('lsb_release -ds 2>/dev/null || cat /etc/*release 2>/dev/null | head -n1 || uname -om');
        }

        return Theme::render('admin.index', [
            'album_count' => $albumCount,
            'app_version' => config('app.version'),
            'comment_count' => $commentCount,
            'group_count' => $groupCount,
            'label_count' => $labelCount,
            'memory_limit' => ini_get('memory_limit'),
            'metadata_upgrade_needed' => $metadataUpgradeNeeded,
            'photo_count' => $photoCount,
            'php_version' => phpversion(),
            'os_version' => $osVersion,
            'server_name' => gethostname(),
            'upload_file_size' => ini_get('upload_max_filesize'),
            'upload_max_limit' => ini_get('post_max_size'),
            'user_count' => $userCount
        ]);
    }

    public function quickUpload(Request $request)
    {
        $this->authorizeAccessToAdminPanel('admin:manage-albums');

        $returnUrl = $request->headers->get('referer');
        if (!MiscHelper::isSafeUrl($returnUrl))
        {
            $returnUrl = route('home');
        }

        // Pre-validate the upload before passing to the Photos controller
        $files = $request->files->get('photo');
        if (!is_array($files) || count($files) == 0)
        {
            $request->session()->flash('error', trans('admin.quick_upload.no_image_provided'));
            return redirect($returnUrl);
        }

        $albumID = $request->get('album_id');
        if (intval($albumID) == 0)
        {
            $albumName = trim($request->get('album_name'));
            if (strlen($albumName) == 0)
            {
                $request->session()->flash('error', trans('admin.quick_upload.no_album_selected'));
                return redirect($returnUrl);
            }

            $albumViews = UserConfig::allowedAlbumViews();

            $album = new Album();
            $album->storage_id = Storage::where('is_default', true)->first()->id;
            $album->user_id = Auth::user()->id;
            $album->default_view = UserConfig::get('default_album_view');
            $album->name = $albumName;
            $album->description = '';
            $album->save();

            $request->request->set('album_id', $album->id);
        }

        /** @var PhotoController $photoController */
        $photoController = app(PhotoController::class);
        return $photoController->store($request);
    }

    public function rebuildPermissionsCache()
    {
        $helper = new PermissionsHelper();
        $helper->rebuildCache();

        return response()->json(true);
    }

    public function saveSettings(SaveSettingsRequest $request)
    {
        $this->authorizeAccessToAdminPanel('admin:configure');

        $checkboxKeys = [
            'albums_menu_parents_only',
            'allow_photo_comments',
            'allow_photo_comments_anonymous',
            'allow_self_registration',
            'enable_visitor_hits',
            'hotlink_protection',
            'moderate_anonymous_users',
            'moderate_known_users',
            'rabbitmq_enabled',
            'recaptcha_enabled_registration',
            'remove_copyright',
            'require_email_verification',
            'restrict_original_download',
            'smtp_encryption',
            'social_facebook_login',
            'social_google_login',
            'social_twitter_login',
            'social_user_feeds',
            'social_user_profiles'
        ];
        $updateKeys = [
            'albums_menu_number_items',
            'app_name',
            'date_format',
            'facebook_app_id',
            'facebook_app_secret',
            'google_app_id',
            'google_app_secret',
            'photo_comments_allowed_html',
            'photo_comments_thread_depth',
            'rabbitmq_server',
            'rabbitmq_port',
            'rabbitmq_username',
            'rabbitmq_password',
            'rabbitmq_queue',
            'sender_address',
            'sender_name',
            'smtp_server',
            'smtp_port',
            'smtp_username',
            'smtp_password',
            'theme',
            'twitter_app_id',
            'twitter_app_secret',
            'recaptcha_site_key',
            'recaptcha_secret_key',
            'analytics_code'
        ];

        $defaults = UserConfig::defaults();

        foreach ($updateKeys as $key)
        {
            $config = UserConfig::getOrCreateModel($key);

            // Bit of a hack when the browser returns an empty password field - meaning the user didn't change it
            // - don't touch it!
            if (
                (
                    $key == 'smtp_password' &&
                    strlen($config->value) > 0 &&
                    strlen($request->request->get($key)) == 0 &&
                    strlen($request->request->get('smtp_username')) > 0
                ) || (
                    $key == 'rabbitmq_password' &&
                    strlen($config->value) > 0 &&
                    strlen($request->request->get($key)) == 0 &&
                    strlen($request->request->get('rabbitmq_username')) > 0
                )
            )
            {
                continue;
            }

            $config->value = $request->request->get($key);
            if (in_array($key, $this->passwordSettingKeys) && strlen($config->value) > 0)
            {
                $config->value = encrypt($config->value);
            }

            if (isset($defaults[$key]) && $defaults[$key] == $config->value)
            {
                $config->delete();
            }
            else
            {
                $config->save();
            }
        }

        foreach ($checkboxKeys as $key)
        {
            $config = UserConfig::getOrCreateModel($key);
            $config->value = ($request->request->get($key) == 'on' ? 1 : 0);

            if (isset($defaults[$key]) && $defaults[$key] == $config->value)
            {
                $config->delete();
            }
            else
            {
                $config->save();
            }
        }

        $request->session()->flash('success', trans('admin.settings_saved_message'));
        return redirect(route('admin.settings'));
    }

    public function settings(Request $request)
    {
        $this->authorizeAccessToAdminPanel('admin:configure');

        // Load the current configuration
        $config = array_merge(UserConfig::defaults(), UserConfig::getAll());

        $dateFormats = UserConfig::allowedDateFormats();
        $dateFormatsLookup = [];

        foreach ($dateFormats as $dateFormat)
        {
            $dateFormatsLookup[$dateFormat] = date($dateFormat);
        }

        foreach ($this->passwordSettingKeys as $passwordSettingKey)
        {
            if (isset($config[$passwordSettingKey]) && !empty($config[$passwordSettingKey]))
            {
                $config[$passwordSettingKey] = decrypt($config[$passwordSettingKey]);
            }
        }

        $themeNamesLookup = UserConfig::allowedThemeNames();

        return Theme::render('admin.settings', [
            'config' => $config,
            'date_formats' => $dateFormatsLookup,
            'success' => $request->session()->get('success'),
            'theme_names' => $themeNamesLookup
        ]);
    }

    public function testMailSettings(SaveSettingsRequest $request)
    {
        $this->authorizeAccessToAdminPanel('admin:configure');

        try
        {
            $validKeys = [
                'sender_address',
                'sender_name',
                'smtp_server',
                'smtp_port',
                'smtp_username',
                'smtp_password',
                'smtp_encryption'
            ];
            $config = $request->only($validKeys);

            /** @var \Swift_Mailer $swiftMailer */
            $swiftMailer = resolve('mailer')->getSwiftMailer();

            /** @var \Swift_SmtpTransport $transport */
            $transport = $swiftMailer->getTransport();
            $transport->setHost($config['smtp_server']);
            $transport->setPort(intval($config['smtp_port']));
            $transport->setUsername($config['smtp_username']);
            $transport->setPassword($config['smtp_password']);

            if (isset($config['smtp_encryption']) && strtolower($config['smtp_encryption']) == 'on')
            {
                $transport->setEncryption('tls');
            }
            else
            {
                $transport->setEncryption('');
            }

            Mail::to(Auth::user())->send(new TestMailConfig($config['sender_name'], $config['sender_address']));

            return response()->json(array('is_successful' => true, 'message' => trans('admin.settings_test_email_successful')));
        }
        catch (\Exception $ex)
        {
            return response()->json(array('is_successful' => false, 'message' => $ex->getMessage()));
        }
    }
}