<?php
namespace Misuzu;

use RuntimeException;
use Misuzu\Auth\AuthTokenBuilder;
use Misuzu\Auth\AuthTokenCookie;
use Misuzu\Auth\AuthTokenInfo;

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',
    'eeprom.path:s',
    'eeprom.app:s',
    ['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'],
    '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);

$tokenPacker = $msz->createAuthTokenPacker();

if(filter_has_var(INPUT_COOKIE, 'msz_auth'))
    $tokenInfo = $tokenPacker->unpack(filter_input(INPUT_COOKIE, 'msz_auth'));
elseif(filter_has_var(INPUT_COOKIE, 'msz_uid') && filter_has_var(INPUT_COOKIE, 'msz_sid')) {
    $tokenBuilder = new AuthTokenBuilder;
    $tokenBuilder->setUserId((string)filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT));
    $tokenBuilder->setSessionToken((string)filter_input(INPUT_COOKIE, 'msz_sid'));
    $tokenInfo = $tokenBuilder->toInfo();
    $tokenBuilder = null;
} else
    $tokenInfo = AuthTokenInfo::empty();

$userInfo = null;
$sessionInfo = null;
$userInfoReal = null;

if($tokenInfo->hasUserId() && $tokenInfo->hasSessionToken()) {
    $users = $msz->getUsers();
    $sessions = $msz->getSessions();
    $tokenBuilder = new AuthTokenBuilder($tokenInfo);

    try {
        $sessionInfo = $sessions->getSession(sessionToken: $tokenInfo->getSessionToken());

        if($sessionInfo->hasExpired()) {
            $tokenBuilder->removeUserId();
            $tokenBuilder->removeSessionToken();
        } elseif($sessionInfo->getUserId() === $tokenInfo->getUserId()) {
            $userInfo = $users->getUser($tokenInfo->getUserId(), 'id');

            if($userInfo->isDeleted()) {
                $tokenBuilder->removeUserId();
                $tokenBuilder->removeSessionToken();
            } else {
                $users->recordUserActivity($userInfo, remoteAddr: $_SERVER['REMOTE_ADDR']);
                $sessions->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $_SERVER['REMOTE_ADDR']);
                if($sessionInfo->shouldBumpExpires())
                    $tokenBuilder->setEdited();

                if($tokenInfo->hasImpersonatedUserId()) {
                    $allowToImpersonate = $userInfo->isSuperUser();
                    $impersonatedUserId = $tokenInfo->getImpersonatedUserId();

                    if(!$allowToImpersonate) {
                        $allowImpersonateUsers = $cfg->getArray(sprintf('impersonate.allow.u%s', $userInfo->getId()));
                        $allowToImpersonate = in_array((string)$impersonatedUserId, $allowImpersonateUsers, true);
                    }

                    if($allowToImpersonate) {
                        $userInfoReal = $userInfo;

                        try {
                            $userInfo = $users->getUser($impersonatedUserId, 'id');
                        } catch(RuntimeException $ex) {
                            $userInfo = $userInfoReal;
                            $userInfoReal = null;
                            $tokenBuilder->removeImpersonatedUserId();
                        }
                    } else $tokenBuilder->removeImpersonatedUserId();
                }
            }
        }
    } catch(RuntimeException $ex) {
        $tokenBuilder->removeUserId();
        $tokenBuilder->removeSessionToken();
        $tokenBuilder->removeImpersonatedUserId();
        $userInfo = null;
        $sessionInfo = null;
        $userInfoReal = null;
    }

    if($tokenBuilder->isEdited()) {
        $tokenInfo = $tokenBuilder->toInfo();
        AuthTokenCookie::apply($tokenPacker->pack($tokenInfo));
    }
}

$msz->getAuthInfo()->setInfo($tokenInfo, $userInfo, $sessionInfo, $userInfoReal);

if(!empty($userInfo))
    $userInfo = $users->getUser((string)$userInfo->getId(), 'id');
if(!empty($userInfoReal))
    $userInfoReal = $users->getUser((string)$userInfoReal->getId(), 'id');

CSRF::init(
    $globals['csrf.secret'],
    ($msz->isLoggedIn() ? $sessionInfo->getToken() : $_SERVER['REMOTE_ADDR'])
);

if(!empty($userInfo)) {
    Template::set('current_user', $userInfo);
    Template::set('current_user_ban_info', $msz->tryGetActiveBan());
}

if(!empty($userInfoReal)) {
    Template::set('current_user_real', $userInfoReal);
    Template::set('current_user_real_colour', $users->getUserColour($userInfoReal));
}

$inManageMode = str_starts_with($_SERVER['REQUEST_URI'], '/manage');

Template::set('header_menu', $msz->getHeaderMenu($userInfo ?? null));
Template::set('user_menu', $msz->getUserMenu($userInfo ?? null, $inManageMode));
Template::set('display_debug_info', MSZ_DEBUG || (!empty($userInfo) && $userInfo->isSuperUser()));

if($inManageMode) {
    $hasManageAccess = $msz->isLoggedIn() && !$msz->hasActiveBan()
        && perms_check_user(MSZ_PERMS_GENERAL, $msz->getActiveUser()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);

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

    Template::set('manage_menu', manage_get_menu($userInfo->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();
$msz->dispatchHttp($request);
