<?php
namespace Misuzu\Users\Assets;

use InvalidArgumentException;
use RuntimeException;
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Misuzu\Perm;
use Misuzu\Auth\AuthInfo;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext;
use Misuzu\Users\UserInfo;

class AssetsRoutes extends RouteHandler {
    public function __construct(
        private AuthInfo $authInfo,
        private URLRegistry $urls,
        private UsersContext $usersCtx
    ) {}

    private function canViewAsset($request, UserInfo $assetUser): bool {
        if($this->usersCtx->getBans()->countActiveBans($assetUser))
            // allow staff viewing profile to still see banned user assets
            // should change the Referer check with some query param only applied when needed
            return $this->authInfo->getPerms('user')->check(Perm::U_USERS_MANAGE)
                && parse_url($request->getHeaderFirstLine('Referer'), PHP_URL_PATH) === $this->urls->format('user-profile');

        return true;
    }

    #[Route('GET', '/assets/avatar')]
    #[Route('GET', '/assets/avatar/:filename')]
    #[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])]
    public function getAvatar($response, $request, string $fileName = '') {
        $userId = pathinfo($fileName, PATHINFO_FILENAME);
        $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC);

        try {
            $userInfo = $this->usersCtx->getUserInfo($userId);

            if(!$this->canViewAsset($request, $userInfo)) {
                $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/banned-avatar.png', MSZ_PUBLIC);
            } else {
                $userAssetInfo = new UserAvatarAsset($userInfo);
                if($userAssetInfo->isPresent())
                    $assetInfo = $userAssetInfo;
            }
        } catch(RuntimeException $ex) {
        } catch(InvalidArgumentException $ex) {}

        $this->serveAsset($response, $request, $assetInfo);
    }

    #[Route('GET', '/assets/profile-background')]
    #[Route('GET', '/assets/profile-background/:filename')]
    #[URLInfo('user-background', '/assets/profile-background/<user>')]
    public function getProfileBackground($response, $request, string $fileName = '') {
        $userId = pathinfo($fileName, PATHINFO_FILENAME);

        try {
            $userInfo = $this->usersCtx->getUserInfo($userId);
        } catch(RuntimeException $ex) {
        } catch(InvalidArgumentException $ex) {}

        if(!empty($userInfo)) {
            $userAssetInfo = new UserBackgroundAsset($userInfo);
            if($userAssetInfo->isPresent() && $this->canViewAsset($request, $userInfo))
                $assetInfo = $userAssetInfo;
        }

        if(!isset($assetInfo)) {
            // circumvent the default error page
            $response->setContent('Not Found');
            return 404;
        }

        $this->serveAsset($response, $request, $assetInfo);
    }

    #[Route('GET', '/user-assets.php')]
    public function getUserAssets($response, $request) {
        $userId = (string)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT);
        $mode = (string)$request->getParam('m');

        if($mode === 'avatar')
            return $this->getAvatar($response, $request, $userId);

        if($mode === 'background')
            return $this->getProfileBackground($response, $request, $userId);

        // circumvent the default error page
        $response->setContent('Not Found');
        return 404;
    }

    private function serveAsset($response, $request, UserImageAssetInterface $assetInfo): void {
        $contentType = $assetInfo->getMimeType();
        $publicPath = $assetInfo->getPublicPath();
        $fileName = $assetInfo->getFileName();

        if($assetInfo instanceof UserAssetScalableInterface) {
            $dimensions = (int)($request->getParam('res', FILTER_SANITIZE_NUMBER_INT)
                ?? $request->getParam('r', FILTER_SANITIZE_NUMBER_INT));

            if($dimensions > 0) {
                $assetInfo->ensureScaledExists($dimensions);
                $contentType = $assetInfo->getScaledMimeType($dimensions);
                $publicPath = $assetInfo->getPublicScaledPath($dimensions);
                $fileName = $assetInfo->getScaledFileName($dimensions);
            }
        }

        $response->accelRedirect($publicPath);
        $response->setContentType($contentType);
        $response->setFileName($fileName, false);
    }
}
