<?php

namespace events\listeners;

use CfPasswordReset;
use CfSettings;
use events\BaseEvents;
use events\dto\UserEventsDto;
use events\EventService;
use SettingsHelper;
use Utils;

class UserEvents extends BaseEvents
{
    public static function registerEvents(): void
    {
        self::passwordChanged();
        self::userUpdated();
        self::invalidateTokensExceptCurrent();
    }

    private static function passwordChanged(): void
    {
        self::updatePasswordResetTime();
        self::invalidateResetPasswordTokensOnPasswordChange();
    }

    private static function userUpdated(): void
    {
        self::invalidateResetPasswordTokensOnEmailUpdate();
    }


    private static function invalidateTokensExceptCurrent(): void
    {
        $resetToken = function (UserEventsDto $user) {
            $server = Utils::getOauthServer();
            $accessTokenStorage = $server->getStorage('access_token');
            $accessTokenStorage->invalidateAllTokensExceptProvided($user->username, $user->oauthToken);
        };
        EventService::addEventListener(BaseEvents::PASSWORD_CHANGED, $resetToken);
        EventService::addEventListener(BaseEvents::TWO_FA_CONFIGURED, $resetToken);
    }

    private static function updatePasswordResetTime(): void
    {
        EventService::addEventListener(BaseEvents::PASSWORD_CHANGED, function (UserEventsDto $user) {
            $cfSettingsService = CfSettings::getInstance();
            $passwordExpiration = $cfSettingsService->getSetting(SettingsHelper::PASSWORD_EXPIRATION_AFTER_RESET_HOURS);
            // if password reset then set expiration time now + RESET_PASSWORD_EXPIRE_AFTER_HOURS
            // if password updated but not reset, then set it to null
            $hoursOffset = $user->isPasswordReset ? $passwordExpiration : null;
            $user->cfUser->setPasswordExpirationTime($hoursOffset);
        });
    }


    private static function invalidateResetPasswordTokensOnPasswordChange(): void
    {
        EventService::addEventListener(BaseEvents::PASSWORD_CHANGED, function (UserEventsDto $user) {
            (new CfPasswordReset())->revokeAllUserTokens($user->username);
        });
    }

    private static function invalidateResetPasswordTokensOnEmailUpdate(): void
    {
        EventService::addEventListener(BaseEvents::USER_UPDATED, function (UserEventsDto $user) {
            if (array_key_exists('email', $user->updatedData)) {
                (new CfPasswordReset())->revokeAllUserTokens($user->username);
            }
        });
    }
}
