<?php
namespace Misuzu;

use RuntimeException;
use Misuzu\Auth\{AuthTokenBuilder,AuthTokenCookie,AuthTokenInfo};

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

set_exception_handler(function(\Throwable $ex) {
    \Sentry\captureException($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;
}

$tokenPacker = $msz->getAuthContext()->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->getUsersContext()->getUsers();
    $sessions = $msz->getAuthContext()->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));
    }
}

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

CSRF::init(
    $cfg->getString('csrf.secret', 'soup'),
    ($authInfo->isLoggedIn() ? $sessionInfo->getToken() : $_SERVER['REMOTE_ADDR'])
);

// order for these two currently matters i think: it shouldn't.
$router = $msz->createRouting();
$msz->startTemplating();

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

if(!empty($mszLegacyPath) && str_starts_with($mszLegacyPath, $mszLegacyPathPrefix)) {
    $mszLegacyPathReal = realpath($mszLegacyPath);
    if($mszLegacyPath === $mszLegacyPathReal || $mszLegacyPath === $mszLegacyPathReal . '/') {
        if(str_starts_with($mszRequestPath, '/manage') && !$msz->hasManageAccess())
            Template::throwError(403);

        if(is_dir($mszLegacyPath))
            $mszLegacyPath .= '/index.php';

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

$router->dispatch($request);