<?php
namespace Misuzu;

use RuntimeException;
use Misuzu\Users\User;
use Misuzu\Users\UserSession;

require_once __DIR__ . '/../misuzu.php';

set_exception_handler(function(\Throwable $ex) {
    http_response_code(500);
    ob_clean();

    if(MSZ_DEBUG) {
        header('Content-Type: text/plain; charset=utf-8');
        echo (string)$ex;
    } else {
        header('Content-Type: text/html; charset=utf-8');
        echo file_get_contents(MSZ_TEMPLATES . '/500.html');
    }
    exit;
});

// The whole wall of shit before the router setup and dispatch should be worked away
// Lockdown things should be middleware when there's no more legacy files

$request = \Index\Http\HttpRequest::fromRequest();

ob_start();

if(file_exists(MSZ_ROOT . '/.migrating')) {
    http_response_code(503);
    if(!isset($_GET['_check'])) {
        header('Content-Type: text/html; charset=utf-8');
        echo file_get_contents(MSZ_TEMPLATES . '/503.html');
    }
    exit;
}

if(!MSZ_DEBUG) {
    $twigCacheDirSfx = GitInfo::hash(true);
    if(empty($twigCacheDirSfx))
        $twigCacheDirSfx = md5(MSZ_ROOT);

    $twigCache = sys_get_temp_dir() . '/msz-tpl-' . $twigCacheDirSfx;
    if(!is_dir($twigCache))
        mkdir($twigCache, 0775, true);
}

$globals = $cfg->getValues([
    ['site.name:s', 'Misuzu'],
    'site.desc:s',
    'site.url:s',
    'sockChat.chatPath.normal:s',
    'eeprom.path:s',
    'eeprom.app:s',
    ['auth.secret:s', 'meow'],
    ['csrf.secret:s', 'soup'],
]);

Template::init($msz, $twigCache ?? null, MSZ_DEBUG);

Template::set('globals', [
    'site_name' => $globals['site.name'],
    'site_description' => $globals['site.desc'],
    'site_url' => $globals['site.url'],
    'site_chat' => $globals['sockChat.chatPath.normal'],
    'eeprom' => [
        'path' => $globals['eeprom.path'],
        'app' => $globals['eeprom.app'],
    ],
]);

$mszAssetsInfo = json_decode(file_get_contents(MSZ_ASSETS . '/current.json'));
if(!empty($mszAssetsInfo))
    Template::set('assets', $mszAssetsInfo);
unset($mszAssetsInfo);

Template::addPath(MSZ_TEMPLATES);

AuthToken::setSecretKey($globals['auth.secret']);

if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
    $authToken = new AuthToken;
    $authToken->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0);
    $authToken->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid') ?? '');

    if($authToken->isValid())
        $authToken->applyCookie(strtotime('1 year'));

    AuthToken::nukeCookieLegacy();
}

if(!isset($authToken))
    $authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth') ?? '');

if($authToken->isValid()) {
    $authToken->setCurrent();

    try {
        $sessionInfo = UserSession::byToken($authToken->getSessionToken());
        if($sessionInfo->hasExpired()) {
            $sessionInfo->delete();
        } elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
            $userInfo = $sessionInfo->getUser();
            if(!$userInfo->isDeleted()) {
                $sessionInfo->setCurrent();
                $userInfo->setCurrent();
                $sessionInfo->bump($_SERVER['REMOTE_ADDR']);

                if($sessionInfo->shouldBumpExpire())
                    $authToken->applyCookie($sessionInfo->getExpiresTime());

                // only allow impersonation when super user
                if($authToken->hasImpersonatedUserId() && $userInfo->isSuper()) {
                    $userInfoReal = $userInfo;

                    try {
                        $userInfo = User::byId($authToken->getImpersonatedUserId());
                    } catch(RuntimeException $ex) {
                        $userInfo = $userInfoReal;
                        $authToken->removeImpersonatedUserId();
                        $authToken->applyCookie();
                    }

                    $userInfo->setCurrent();
                }
            }
        }
    } catch(RuntimeException $ex) {
        UserSession::unsetCurrent();
        User::unsetCurrent();
    }

    if(UserSession::hasCurrent()) {
        $userInfo->bumpActivity($_SERVER['REMOTE_ADDR']);
    } else
        AuthToken::nukeCookie();
}

CSRF::init(
    $globals['csrf.secret'],
    (UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : ($_SERVER['REMOTE_ADDR'] ?? '::1'))
);

if(!empty($userInfo))
    Template::set('current_user', $userInfo);
if(!empty($userInfoReal))
    Template::set('current_user_real', $userInfoReal);

$inManageMode = str_starts_with($_SERVER['REQUEST_URI'], '/manage');
$hasManageAccess = User::hasCurrent()
    && !User::getCurrent()->hasActiveWarning()
    && perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
Template::set('has_manage_access', $hasManageAccess);

if($inManageMode) {
    if(!$hasManageAccess) {
        echo render_error(403);
        exit;
    }

    Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
}

$mszRequestPath = $request->getPath();
$mszLegacyPathPrefix = MSZ_PUBLIC . '-legacy/';
$mszLegacyPath = realpath($mszLegacyPathPrefix . $mszRequestPath);

if(!empty($mszLegacyPath) && str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) {
    if(is_dir($mszLegacyPath))
        $mszLegacyPath .= '/index.php';

    if(is_file($mszLegacyPath)) {
        require_once $mszLegacyPath;
        return;
    }
}

$msz->setUpHttp(str_contains($mszRequestPath, '.php'));
$msz->dispatchHttp($request);
