<?php

/*
 * This file is part of Chevereto.
 *
 * (c) Rodolfo Berrios <rodolfo@chevereto.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Chevere\Http\Exceptions\ControllerException;
use Chevere\Parameter\Interfaces\TypeInterface;
use Chevere\Parameter\Type;
use Chevere\Router\Container;
use Chevere\Writer\NullWriter;
use Chevereto\Config\Config;
use Chevereto\Legacy\Classes\Cache;
use Chevereto\Legacy\Classes\Categories;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Fonts;
use Chevereto\Legacy\Classes\IpBan;
use Chevereto\Legacy\Classes\L10n;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Page;
use Chevereto\Legacy\Classes\Palettes;
use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\Tags;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Nyholm\Psr7\Factory\Psr17Factory;
use function Chevere\Parameter\getType;
use function Chevere\Router\router;
use function Chevereto\Encryption\encryption;
use function Chevereto\Legacy\badgePaid;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Legacy\editionCombo;
use function Chevereto\Legacy\G\absolute_to_url;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_current_url;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\is_route_available;
use function Chevereto\Legacy\G\is_url;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\set_status_header;
use function Chevereto\Legacy\get_enabled_languages;
use function Chevereto\Legacy\getPoweredByRemarks;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\getSystemNotices;
use function Chevereto\Legacy\getVariable;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Legacy\headersResetCache;
use function Chevereto\Legacy\include_peafowl_head;
use function Chevereto\Legacy\is_max_invalid_request;
use function Chevereto\Vars\cookie;
use function Chevereto\Vars\env;
use function Chevereto\Vars\files;
use function Chevereto\Vars\get;
use function Chevereto\Vars\post;
use function Chevereto\Vars\server;
use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;

$isService = env()['CHEVERETO_ENABLE_TENANTS'] === '1'
    || env()['CHEVERETO_TENANT'] !== ''
    || env()['CHEVERETO_CONTEXT'] === 'saas';
$tenantsApiRouting = [
    '/_/',
];
$isTenantsApiRouting = false;
foreach ($tenantsApiRouting as $route) {
    if (str_starts_with(server()['REQUEST_URI'] ?? '', $route)) {
        $isTenantsApiRouting = true;

        break;
    }
}
if ($isTenantsApiRouting) {
    $container = new Container(
        db: DB::getInstance(),
        redis: Cache::instance()->redis(),
        encryption: encryption(),
        logger: new NullWriter(),
        cachePrefix: env()['CHEVERETO_CACHE_KEY_PREFIX'],
    );
    $psr17Factory = new Psr17Factory();
    $method = server()['REQUEST_METHOD']
        ?? throw new RuntimeException('Cannot determine request method.');
    $scheme = server()['REQUEST_SCHEME']
        ?? throw new RuntimeException('Cannot determine request scheme.');
    $host = server()['HTTP_HOST']
        ?? throw new RuntimeException('Cannot determine request host.');
    $uri = server()['REQUEST_URI']
        ?? '/';
    $serverRequest = $psr17Factory
        ->createServerRequest(
            method: $method,
            uri: $scheme
                . '://'
                . $host
                . $uri,
            serverParams: server(),
        )
        ->withCookieParams(
            cookies: cookie()
        )
        ->withQueryParams(
            query: get()
        )
        ->withUploadedFiles(
            uploadedFiles: files()
        )
        ->withParsedBody(
            data: post()
        )
        ->withBody(
            body: $psr17Factory->createStream(
                content: file_get_contents('php://input')
            )
        );
    $headers = getallheaders();
    foreach ($headers as $name => $value) {
        $serverRequest = $serverRequest->withHeader($name, $value);
    }
    $router = router(require dirname(__DIR__, 2) . '/routes/tenants-api-v4.php');
    $container = $container->withAutoInject(
        $router->dependencies(),
    );
    $routed = $router->getRouted($serverRequest, $psr17Factory, container: $container);
    if ($routed->hasThrowable()
        && ! ($routed->throwable() instanceof ControllerException)
    ) {
        throw $routed->throwable();
    }
    $returnType = new Type(getType($routed->return()));
    $response = $routed->response();
    $statusCode = $response->getStatusCode();
    $controllerName = $routed->bind()->controllerName();
    if ($response->hasHeader('Location')) {
        (new SapiEmitter())->emit($response);
        exit();
    }
    $context = [];
    $view = $routed->bind()->view();
    if ($routed->hasThrowable()) {
        $throwable = $routed->throwable();
        $errorMessage = $throwable->getMessage();
        $errorMessage = $errorMessage === '' ? null : $errorMessage;
        $errorCode = $throwable->getCode();
        $context['error'] = [
            'code' => $errorCode,
            'message' => $errorMessage,
            'list' => $errorMessage ? explode("\n", $errorMessage) : null,
        ];
    } elseif ($statusCode >= 400 && $statusCode < 500) { // Middleware short-circuit
        $error = $response->getHeaderLine('X-Error');
        $errorMessage = $response->getReasonPhrase();
        $errorMessage = $errorMessage === '' ? null : $errorMessage;
        $context['error'] = [
            'code' => $statusCode,
            'message' => $errorMessage,
            'list' => $errorMessage ? explode("\n", $errorMessage) : null,
        ];
        if ($error !== '' && $response->getHeaderLine('X-Error') === '') {
            $response = $response
                ->withHeader('X-Error', $error);
        }
    }
    $content = '';
    if ($routed->bind()->view() === ''
        || $response->getBody()->getSize() > 0
    ) {
        $view = '';
        $content = $response->getBody()->getContents();
        if ($content === '' && isset($errorMessage)) {
            $status = [
                'status' => [
                    'code' => $statusCode,
                    'message' => $errorMessage,
                ],
                'error' => [
                    'code' => $errorCode ?? null,
                    'list' => $context['error']['list'] ?? null,
                ],
            ];
            $content = json_encode($status, JSON_PRETTY_PRINT);
        }
        $content .= match (true) {
            $returnType->primitive() === 'null' => '',
            $returnType->isScalar() => (string) $routed->return(),
            $returnType->primitive() !== TypeInterface::RESOURCE => json_encode(
                $routed->return(),
                JSON_PRETTY_PRINT
            ),
            default => '',
        };
    }
    $response = $response->withBody(
        $psr17Factory->createStream($content)
    );
    if (! $response->hasHeader('Content-Type')
        && isset($content[0])
        && (
            ($content[0] === '{' && $content[-1] === '}') ||
            ($content[0] === '[' && $content[-1] === ']')
        )
    ) {
        $response = $response->withHeader('Content-Type', 'application/json');
    }
    (new SapiEmitter())->emit($response);
    exit();
}
if (cheveretoVersionInstalled() === '') {
    if ($isService) {
        set_status_header(503);
        echo 'Chevereto is being provisioned. Please check back later.';
        exit();
    }
    new Handler(
        loadTemplate: ! REPL,
        before: function ($handler) {
            headersNoCache();
            if ($handler->requestArray()[0] !== 'install') {
                redirect('install', 302);
            }
        },
    );
}
$hook_before = function (Handler $handler) {
    $dayCacheRoutes = [
        'webmanifest',
    ];
    $exitEarlyRoutes = [
        'webmanifest',
    ];
    $doNotCacheRoutes = [
        'login',
        'signup',
        'logout',
        'account',
        'connect',
        'json',
        'api',
        'captcha-verify',
        'oembed',
        'upload',
        'dashboard',
        'install',
        'settings',
        'redirect',
    ];
    $doNotCheckBanRoutes = [
        'webmanifest',
    ];
    header('Permissions-Policy: unload=()');
    header('Permissions-Policy: interest-cohort=()');
    header("Content-Security-Policy: frame-ancestors 'none'");
    if (! in_array($handler->requestArray()[0], $doNotCheckBanRoutes, true)) {
        $bannedIp = IpBan::getSingle();
        if ($bannedIp !== []) {
            headersNoCache();
            // TODO: Cache until ban expires
            if (is_url($bannedIp['message'] ?? false)) {
                redirect($bannedIp['message'], 301);
            } else {
                $exitMessage = $bannedIp['message'] ?? '';
                $exitMessage = match ($exitMessage) {
                    '' => _s('You have been forbidden to use this website.'),
                    default => $bannedIp['message'],
                };
                exit($exitMessage);
            }
        }
    }
    $cache_ttl = (int) max(0, getSetting('cache_ttl') ?? 0);
    if (in_array($handler->requestArray()[0], $dayCacheRoutes, true)) {
        $cache_ttl = 86400; // 1 day
    }
    if (in_array($handler->requestArray()[0], $doNotCacheRoutes, true)) {
        headersNoCache();
    } elseif ($cache_ttl > 0) {
        headersResetCache();
        header("Cache-Control: private, max-age={$cache_ttl}");
    }
    if (in_array($handler->requestArray()[0], $exitEarlyRoutes, true)) {
        return;
    }
    $failTriggers = [
        'account-password-forgot',
        'account-two-factor',
        'login',
        'signup',
    ];
    $failed_access_requests = RequestLog::getCounts($failTriggers, 'fail');
    if (is_max_invalid_request($failed_access_requests['day'])) {
        set_status_header(403);
    } else {
        Login::tryLogin();
    }
    $user_cookie_lang = cookie()['USER_SELECTED_LANG'] ?? null;
    $user_lang = $user_cookie_lang ?? getSetting('default_language');
    if (Login::isLoggedUser()) {
        $user_lang = Login::getUser()['language'];
        if (Login::getUser()['status'] === 'banned') {
            set_status_header(403);
        }
        if (sessionVar()->has('challenge_two_factor')
            && ! in_array($handler->getRoutePath(), ['account/two-factor', 'captcha-verify', 'logout'], true)
            && $handler->requestArray()[0] !== 'page'
        ) {
            headersNoCache();
            redirect('account/two-factor', 302);
        }
    }
    if (! getSetting('language_chooser_enable')) {
        $user_lang = getSetting('default_language');
    }
    new L10n(
        $user_lang,
        (Login::isLoggedUser() || $user_cookie_lang !== null)
            ? false
            : getSetting('auto_language')
    );
    if (http_response_code() === 403) {
        headersNoCache();
        echo '403 Forbidden';
        exit();
    }
    if ($handler->requestArray()[0] !== 'api'
        && Settings::get('enable_uploads_url') && ! Login::isAdmin()) {
        Settings::setValue('enable_uploads_url', 0);
    }
    if (isset(get()['lang'])
        && array_key_exists(get()['lang'], get_enabled_languages())
    ) {
        L10n::setCookieLang(get()['lang']);
        L10n::processTranslation(get()['lang']);
        define('PUSH_LANG', get()['lang']);
    }
    if (array_key_exists('agree-consent', get())) {
        setcookie(
            'AGREE_CONSENT',
            '1',
            time() + (60 * 60 * 24 * 30),
            Config::host()->hostnamePath()
        );
        sessionVar()->put('agree-consent', true);
        headersNoCache();
        redirect(get_current_url(true, ['agree-consent']), 302);
    }
    $base = $handler::baseRequest();
    parse_str(server()['QUERY_STRING'] ?? '', $querystr);
    $handler::setVar('auth_token', $handler::getAuthToken());
    $handler::setVar('doctitle', getSetting('website_name'));
    $handler::setVar('meta_description', getSetting('website_description'));
    $handler::setVar('logged_user', Login::getUser());
    $handler::setVar('failed_access_requests', $failed_access_requests);
    $handler::setVar('header_logo_link', get_base_url());
    $handler::setCond('admin', Login::isAdmin());
    $handler::setCond('manager', Login::isManager());
    $showContentManager = Login::isAdmin() || Login::isManager();
    $handler::setCond('content_manager', $showContentManager);
    $allowed_nsfw_flagging = ! getSetting('image_lock_nsfw_editing');
    if ($handler::cond('content_manager')) {
        $moderateLink = get_base_url('moderate');
        $moderateLabel = _s('Moderate');
        if (! in_array('pro', editionCombo()[env()['CHEVERETO_EDITION']], true)) {
            if ((bool) env()['CHEVERETO_ENABLE_EXPOSE_PAID_FEATURES']) {
                $moderateLink = 'https://chevereto.com/pricing';
                $moderateLabel .= ' ' . badgePaid('pro');
            } else {
                $showContentManager = false;
            }
        }
        $handler::setVar('moderate_link', $moderateLink);
        $handler::setVar('moderate_label', $moderateLabel);
        $allowed_nsfw_flagging = true;
    }
    $handler::setCond('show_content_manager', $showContentManager);
    $handler::setCond('allowed_nsfw_flagging', $allowed_nsfw_flagging);
    $handler::setCond('maintenance', getSetting('maintenance') and ! Login::isAdmin());
    $handler::setCond(
        'show_consent_screen',
        $base !== 'api' && (
            getSetting('enable_consent_screen')
            ? ! (Login::getUser() || isset(session()['agree-consent']) || isset(cookie()['AGREE_CONSENT']))
            : false
        )
    );
    $handler::setCond('captcha_needed', getSetting('captcha') && getSetting('captcha_threshold') === 0);
    $handler::setCond('show_header', ! ($handler::cond('maintenance') || $handler::cond('show_consent_screen')));
    $handler::setCond('show_notifications', getSetting('website_mode') === 'community' && (getSetting('enable_followers') || getSetting('enable_likes')));
    $handler::setCond('allowed_to_delete_content', Login::isAdmin() || getSetting('enable_user_content_delete'));
    $handler::setVar('canonical', null);
    $palettes = new Palettes();
    $handler::setVar('palettes', $palettes);
    $fonts = new Fonts();
    $handler::setVar('fonts', $fonts);
    $fontId = intval(getSetting('theme_font') ?? 0);
    $handler::setVar('theme_font', $fontId);
    if (in_array($handler->requestArray()[0], ['login', 'signup', 'account'], true)) {
        $paletteId = 0;
    } else {
        $paletteId = Login::isLoggedUser() & Settings::get('theme_palette_user_select')
            ? Login::getUser()['palette_id']
            : Settings::get('theme_palette');
    }
    $theme_palette_handle = $palettes->getHandle(intval($paletteId));
    if ($theme_palette_handle === '') {
        $paletteId = 1;
        $theme_palette_handle = $palettes->getHandle(intval($paletteId));
    }
    $handler::setVar('theme_palette', $paletteId);
    $handler::setVar('theme_palette_handle', $theme_palette_handle);
    if ($handler::cond('maintenance')
        && $handler->requestArray()[0] === 'dashboard') {
        headersNoCache();
        redirect('login', 302);
    }
    $langLinks = [];
    $langToggleUrl = get_current_url(true, ['lang']);
    parse_str(server()['QUERY_STRING'] ?? '', $qs);
    unset($qs['lang']);
    $qs = http_build_query($qs);
    $langLinks['x-default'] = [
        'hreflang' => 'x-default',
        'name' => 'x-default',
        'url' => get_public_url($langToggleUrl),
    ];
    $langToggleUrl = rtrim($langToggleUrl, '/') . ($qs ? '&' : '/?') . 'lang=';
    foreach (get_enabled_languages() as $k => $v) {
        $hreflang = strtolower($k);
        $langUrl = $langToggleUrl . $k;
        $langLinks[$k] = [
            'hreflang' => $hreflang,
            'name' => $v['name'],
            'url' => get_public_url($langUrl),
        ];
    }
    $handler::setVar('langLinks', $langLinks);
    if ($handler::cond('show_consent_screen')) {
        $hasQs = parse_url(get_current_url(), PHP_URL_QUERY) !== null;
        $consent_accept_url = get_current_url()
            . ($hasQs ? '&' : '/?')
            . 'agree-consent';
        $consent_accept_url = '/' . ltrim($consent_accept_url, '/');
        $handler::setVar(
            'consent_accept_url',
            $consent_accept_url
        );
    }
    if (! Login::getUser()) {
        if (getSetting('captcha') && $failed_access_requests['day'] >= getSetting('captcha_threshold')) {
            $handler::setCond('captcha_needed', true);
        }
    }
    $versionInstalled = cheveretoVersionInstalled();
    $pages_link_visible = [];
    if (version_compare($versionInstalled, '3.6.7', '>=')) {
        $cachedPagesVisibleRows = Cache::instance()->get('pages_visible');
        if ($cachedPagesVisibleRows === false) {
            $pagesVisibleRows = Page::getAll(
                args: [
                    'is_active' => '1',
                    'is_link_visible' => '1',
                ],
                sort: [
                    'field' => 'sort_display',
                    'order' => 'ASC',
                ]
            );
            $posPageTos = array_search('tos', array_column($pagesVisibleRows, 'internal'));
            $posPagePrivacy = array_search('privacy', array_column($pagesVisibleRows, 'internal'));
            Cache::instance()->set(
                'pages_visible',
                [
                    'rows' => $pagesVisibleRows,
                    'pos_page_tos' => $posPageTos,
                    'pos_page_privacy' => $posPagePrivacy,
                ],
                3600
            );
        } else {
            $pagesVisibleRows = $cachedPagesVisibleRows['rows'] ?? [];
            $posPageTos = $cachedPagesVisibleRows['pos_page_tos'] ?? false;
            $posPagePrivacy = $cachedPagesVisibleRows['pos_page_privacy'] ?? false;
        }
        $pageTos = $posPageTos === false ? null : $pagesVisibleRows[$posPageTos];
        $pagePrivacy = $posPagePrivacy === false ? null : $pagesVisibleRows[$posPagePrivacy];
        $handler::setVar('page_tos', $pageTos);
        $handler::setVar('page_privacy', $pagePrivacy);
    }
    if ((bool) env()['CHEVERETO_ENABLE_PAGES']) {
        foreach ($pagesVisibleRows ?? [] as $k => $v) {
            if (! ($v['is_active'] ?? false) && ! ($v['is_link_visible'] ?? false)) {
                continue;
            }
            $pages_link_visible[$v['id']] = $v;
        }
    }
    if ($handler::getRoutePath() === 'powered-by') {
        header('Content-Type: text/html; charset=utf-8');
        header('X-Powered-By: Chevereto 4');
        [$about, $liability, $content] = getPoweredByRemarks($handler);
        $logo = absolute_to_url(PATH_PUBLIC_CONTENT_LEGACY_SYSTEM . 'chevereto-blue.svg');
        $website_name = safe_html(getSetting('website_name') ?: 'Chevereto');
        echo <<<PLAIN
        <!DOCTYPE HTML>
        <html>
        <head>
        PLAIN;
        include_peafowl_head();
        echo <<<PLAIN
            <meta charset="utf-8">
            <title>{$website_name} - Powered by Chevereto</title>
            <meta name="apple-mobile-web-app-status-bar-style" content="black">
            <meta name="apple-mobile-web-app-title" content="{$website_name}">
            <meta name="mobile-web-app-capable" content="yes">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="generator" content="Chevereto 4">
        </head>
        <style>
        body {
            min-width: 320px;
        }
        .powered-by p {
            margin: 10px 0;
            line-height: 1.4;
        }
        .powered-by--vendor {
            font-size: 1em;
        }
        .powered-by--vendor a {
            color: inherit;
        }
        .powered-by--vendor img {
            width: 100%;
            max-width: 212px;
            height: auto;
        }
        .powered-by--fine-print {
            font-size: 75% !important;
            text-align: justify;
            opacity: 0.7;
            text-transform: uppercase;
        }
        .powered-by--fine-print a {
            text-decoration: underline;
        }
        </style>
        <body class="padding-20">
            <div class="powered-by powered-by--vendor c12">
                <div class="display-inline-block margin-left-auto margin-right-auto text-center"><a href="https://chevereto.com/" target="_blank" rel="nofollow"><img src="{$logo}" alt="Chevereto"></a></div>
                <p><a href="https://chevereto.com/" target="_blank" class="btn btn-small default text-transform-uppercase"><span class="fas fa-power-off"></span> chevereto.com</a></p>
                <div class="powered-by--fine-print phone-c1 phablet-c1">
                    <p>{$about}</p>
                    <p>{$liability}</p>
                    <p>{$content}</p>
                </div>
            </div>
        </body>
        </html>
        PLAIN;
        exit();
    }
    if (getSetting('website_mode') === 'personal') {
        $userMapPaths = ['search'];
        $userMapPaths[] = getSetting('user_profile_view') === 'files'
            ? 'albums'
            : 'files';
        if ($handler->requestArray()[0] === '/'
            && getSetting('website_mode_personal_routing') === '/'
            && in_array(key($querystr), ['random'], true)
        ) {
            $handler->mapRoute('index');
        } elseif ($handler->requestArray()[0] === 'search'
            && in_array($handler->requestArray()[1] ?? [], ['images', 'albums', 'users'], true)
        ) {
            $handler->mapRoute('search');
        } elseif ($handler->requestArray()[0] === getSetting('website_mode_personal_routing')
            || (getSetting('website_mode_personal_routing') === '/'
            && in_array($handler->requestArray()[0], $userMapPaths, true))
        ) {
            $handler->mapRoute('user', [
                'id' => getSetting('website_mode_personal_uid'),
            ]);
        }
        if ($handler->requestArray()[0] === '/'
            && ! in_array(key($querystr), ['random', 'lang'], true)
            && ! $handler::cond('mapped_route')
        ) {
            $personal_mode_user = User::getSingle(getSetting('website_mode_personal_uid'));
            if ($personal_mode_user !== []) {
                if (Settings::get('homepage_cta_html') === null) {
                    Settings::setValue('homepage_cta_html', _s('View all my images'));
                }
                if (Settings::get('homepage_title_html') === null) {
                    Settings::setValue('homepage_title_html', $personal_mode_user['name']);
                }
                if (Settings::get('homepage_paragraph_html') === null) {
                    Settings::setValue('homepage_paragraph_html', _s('Feel free to browse and discover all my shared images and albums.'));
                }
                if (Settings::get('homepage_cta_fn') !== 'cta-link') {
                    Settings::setValue('homepage_cta_fn', 'cta-link');
                    Settings::setValue('homepage_cta_fn_extra', $personal_mode_user['url']);
                }
                if ($personal_mode_user['background']['url'] ?? false) {
                    Settings::setValue('homepage_cover_image', $personal_mode_user['background']['url']);
                }
            }
        }
    } else {
        if ($base !== 'index' and ! is_route_available($handler->requestArray()[0])) {
            $mapTo = getSetting('root_route');
            $handler->mapRoute($mapTo);
        }
    }
    $virtual_routes = ['image', 'album', 'user', 'video', 'audio'];
    if (in_array($handler->requestArray()[0], $virtual_routes, true)) {
        $virtual_route = getSetting('route_' . $handler->requestArray()[0]);
        if ($handler->requestArray()[0] !== $virtual_route) {
            $virtualized_url = str_replace(
                get_base_url($handler->requestArray()[0]),
                get_base_url($virtual_route),
                get_current_url()
            );
            redirect($virtualized_url, 301);

            return;
        }
    }
    if ($base !== 'index' && ! is_route_available($handler->requestArray()[0])) {
        foreach ($virtual_routes as $k) {
            if ($handler->requestArray()[0] === getSetting('route_' . $k)) {
                $handler->mapRoute($k);
            }
        }
    }
    if (getSetting('website_privacy_mode') === 'private' && ! Login::getUser()) {
        $allowed_requests = ['api', 'login', 'logout', 'page', 'account', 'connect', 'json', 'captcha-verify'];
        foreach ($virtual_routes as $v) {
            $v = getSetting('route_' . $v);
            if (isset($v)) {
                $allowed_requests[] = $v;
            }
        }
        if (getSetting('enable_signups')) {
            $allowed_requests[] = 'signup';
        }
        if (! in_array($handler->requestArray()[0], $allowed_requests, true)) {
            headersNoCache();
            redirect('login', 302);
        }
    }
    $handler::setCond(
        'private_gate',
        getSetting('website_privacy_mode') === 'private'
            && ! Login::getUser()
    );
    $handler::setCond(
        'forced_private_mode',
        getSetting('website_privacy_mode') === 'private'
            && getSetting('website_content_privacy_mode') !== 'default'
    );
    $handler::setCond(
        'explore_enabled',
        $handler::cond('content_manager')
            ?: (getSetting('website_explore_page')
                ? ((bool) Login::isLoggedUser() ?: getSetting('website_explore_page_guest'))
                : false)
    );
    $handler::setCond(
        'search_enabled',
        $handler::cond('content_manager')
            ?: (
                getSetting('website_search')
                && (Login::isLoggedUser() ?: getSetting('website_search_guest'))
            )
    );
    $handler::setCond(
        'random_enabled',
        getSetting('website_random')
        && (Login::isLoggedUser() ?: getSetting('website_random_guest'))
    );
    $moderate_uploads = false;
    switch (getSetting('moderate_uploads')) {
        case 'all':
            $moderate_uploads = ! $handler::cond('content_manager');

            break;
        case 'guest':
            $moderate_uploads = ! Login::isLoggedUser();

            break;
    }
    $handler::setCond('moderate_uploads', $moderate_uploads);
    $categories = [];
    $tagsTop = [];
    if ($handler::cond('explore_enabled') || $base === 'dashboard') {
        $categories = Categories::get();
        $tagsTop = Tags::top();
    }
    $handler::setVar('categories', $categories);
    $handler::setVar('tags_top', $tagsTop);
    $explore_discovery = [
        'recent' => [
            'label' => _s('Recent'),
            'icon' => 'fas fa-history',
        ],
        'trending' => [
            'label' => _s('Trending'),
            'icon' => 'fas fa-chart-simple',
        ],
        'popular' => [
            'label' => _s('Popular'),
            'icon' => 'fas fa-heart',
        ],
    ];
    $explore_content = [
        'images' => [
            'label' => _n('Image', 'Images', 20),
            'icon' => 'fas fa-image',
        ],
        'videos' => [
            'label' => _n('Video', 'Videos', 20),
            'icon' => 'fas fa-video',
        ],
        'animated' => [
            'label' => _s('Animated'),
            'icon' => 'fas fa-play',
        ],
        'tags' => [
            'label' => _n('Tag', 'Tags', 20),
            'icon' => 'fas fa-tags',
        ],
        'albums' => [
            'label' => _n('Album', 'Albums', 20),
            'icon' => 'fas fa-photo-film',
        ],
        'users' => [
            'label' => _n('User', 'Users', 20),
            'icon' => 'fas fa-users',
        ],
    ];
    if (Login::isLoggedUser() && getSetting('enable_followers')) {
        $explore_discovery['following'] = [
            'label' => _s('Following'),
            'icon' => 'fas fa-rss',
            'url' => get_base_url('following'),
        ];
    }
    if (! getSetting('enable_likes')) {
        unset($explore_discovery['popular']);
    }
    foreach ($explore_discovery as $k => &$v) {
        $v['url'] = get_base_url('explore/' . $k);
    }
    foreach ($explore_content as $k => &$v) {
        $v['url'] = get_base_url('explore/' . $k);
    }
    unset($v);
    $handler::setVar('explore_discovery', $explore_discovery);
    $handler::setVar('explore_content', $explore_content);

    $apiEnabled = ((bool) env()['CHEVERETO_ENABLE_API_USER'] || (bool) env()['CHEVERETO_ENABLE_API_GUEST'])
        && (getSetting('enable_api_user') || getSetting('enable_api_guest'));
    $handler::setCond('api_enabled', $apiEnabled);
    if ($apiEnabled) {
        $api_page = [
            'type' => 'link',
            'link_url' => get_base_url('api-v1'),
            'icon' => 'fas fa-project-diagram',
            'title' => 'API',
            'is_active' => 1,
            'is_link_visible' => 1,
            'attr_target' => '_self',
            'sort_display' => -2,
        ];
        Page::fill($api_page);
        $pages_link_visible[] = $api_page;
    }
    if (getSetting('enable_plugin_route')) {
        $plugin_page = [
            'type' => 'link',
            'link_url' => get_base_url('plugin'),
            'icon' => 'fas fa-plug-circle-plus',
            'title' => _s('Plugin'),
            'is_active' => 1,
            'is_link_visible' => 1,
            'attr_target' => '_self',
            'sort_display' => -1,
        ];
        Page::fill($plugin_page);
        $pages_link_visible[] = $plugin_page;
    }
    uasort($pages_link_visible, function ($a, $b) {
        return $a['sort_display'] - $b['sort_display'];
    });
    $handler::setVar('pages_link_visible', $pages_link_visible);
    $upload_enabled = Login::isAdmin() ?: getSetting('enable_uploads');
    $upload_allowed = $upload_enabled;
    if (! Login::getUser()) {
        if (! getSetting('guest_uploads') || getSetting('website_privacy_mode') === 'private' || $handler::cond('maintenance')) {
            $upload_allowed = false;
        }
    } elseif (! Login::isAdmin() && getSetting('website_mode') === 'personal' && getSetting('website_mode_personal_uid') !== Login::getUser()['id']) {
        $upload_allowed = false;
    }
    if ((! (bool) env()['CHEVERETO_ENABLE_LOCAL_STORAGE']) && getVariable('storages_active')->nullInt() === 0) {
        $upload_enabled = false;
        $upload_allowed = false;
    }
    if (! Login::getUser() && $upload_allowed && getSetting('upload_max_filesize_mb_guest')) {
        Settings::setValue('upload_max_filesize_mb_bak', getSetting('upload_max_filesize_mb'));
        Settings::setValue('upload_max_filesize_mb', getSetting('upload_max_filesize_mb_guest'));
    }
    if ($upload_allowed
        && in_array($handler->requestArray()[0], ['login', 'signup', 'account'], true)
    ) {
        $upload_allowed = false;
    }
    $handler::setCond('upload_enabled', $upload_enabled); // System allows to upload?
    $handler::setCond('upload_allowed', $upload_allowed); // Current user can upload?
    if ($handler::cond('maintenance') || $handler::cond('show_consent_screen')) {
        $handler::setCond('private_gate', true);
        $allowed_requests = ['login', 'account', 'connect', 'captcha-verify', 'oembed'];
        if (! in_array($handler->requestArray()[0], $allowed_requests, true)) {
            $handler->preventRoute($handler::cond('show_consent_screen') ? 'consent-screen' : 'maintenance');
        }
    }
    $handler::setVar('system_notices', Login::isAdmin() ? getSystemNotices() : []);
    $excludeLastUrl = [
        'login',
        'signup',
        'account',
        'connect',
        'logout',
        'json',
        'api',
        'captcha-verify',
        'webmanifest',
        'tag-autocomplete',
    ];
    if (! in_array($handler->requestArray()[0], $excludeLastUrl, true)) {
        sessionVar()->put('last_url', get_current_url());
    }
    $detect = new Mobile_Detect();
    $isMobile = $detect->isMobile();
    $handler::setCond('mobile_device', (bool) $isMobile);
    $handler::setCond('show_viewer_zero', false);
    if ($handler->template() === 'request-denied') {
        $handler::setVar('doctitle', _s('Request denied') . ' (403) - ' . getSetting('website_name'));
        $handler->preventRoute('request-denied');
    }
    $handler::setVar('tos_privacy_agreement', _s('I agree to the %terms_link and %privacy_link', [
        '%terms_link' => '<a ' . ($handler::var('page_tos')['link_attr'] ?? '') . '>' . _s('terms') . '</a>',
        '%privacy_link' => '<a ' . ($handler::var('page_privacy')['link_attr'] ?? '') . '>' . _s('privacy policy') . '</a>',
    ]));
    $show_powered_by_footer = getSetting('enable_powered_by');
    if (array_key_exists('CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER', env())) {
        if ((bool) env()['CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER']) {
            $show_powered_by_footer = true;
        }
    }
    $handler::setCond('show_powered_by_footer', $show_powered_by_footer);
};
$hook_after = function (Handler $handler) {
    if (array_key_exists('deleted', get())
            && in_array($handler->template(), ['user', 'album'], true)
    ) {
        set_status_header(303);
    }
    if ($handler->template() === '404') {
        if (sessionVar()->has('last_url')) {
            sessionVar()->remove('last_url');
        }
        $handler::setVar('doctitle', _s("That page doesn't exist") . ' (404) - ' . getSetting('website_name'));
    }
    $list_params = $handler::var('list_params');
    if (isset($list_params) && $list_params['page_show']) {
        $handler::setVar('doctitle', $handler::var('doctitle') . ' | ' . _s('Page %s', $list_params['page_show']));
    }
    if (defined('PUSH_LANG')) {
        $handler::setVar('doctitle', $handler::var('doctitle') . ' (' . get_enabled_languages()[PUSH_LANG]['name'] . ')');
    }
    $handler::setVar('safe_html_website_name', getSetting('website_name', true));
    $handler::setVar('safe_html_doctitle', safe_html($handler::var('doctitle')));
    if ($handler::var('pre_doctitle')) {
        $handler::setVar('safe_html_pre_doctitle', safe_html($handler::var('pre_doctitle')));
    }
    if ($handler::var('meta_description')) {
        $handler::setVar('safe_html_meta_description', safe_html($handler::var('meta_description')));
    }
    if ($handler::var('meta_keywords')) {
        $handler::setVar('safe_html_meta_keywords', safe_html($handler::var('meta_keywords')));
    }
    sessionVar()->put('REQUEST_REFERER', get_current_url());
    header('X-Powered-By: Chevereto 4');
};
new Handler(loadTemplate: ! REPL, before: $hook_before, after: $hook_after);
