<?php
namespace Misuzu;

use RuntimeException;
use Index\Colour\Colour;
use Misuzu\Perm;
use Misuzu\Auth\AuthTokenCookie;
use Misuzu\Users\User;

$authInfo = $msz->getAuthInfo();
$viewerPerms = $authInfo->getPerms('user');
if(!$authInfo->isLoggedIn())
    Template::throwError(403);

$urls = $msz->getURLs();
$usersCtx = $msz->getUsersContext();
$users = $usersCtx->getUsers();
$roles = $usersCtx->getRoles();
$perms = $msz->getPerms();

$currentUser = $authInfo->getUserInfo();

$canManageUsers = $viewerPerms->check(Perm::U_USERS_MANAGE);
$canManagePerms = $viewerPerms->check(Perm::U_PERMS_MANAGE);
$canManageNotes = $viewerPerms->check(Perm::U_NOTES_MANAGE);
$canManageWarnings = $viewerPerms->check(Perm::U_WARNINGS_MANAGE);
$canManageBans = $viewerPerms->check(Perm::U_BANS_MANAGE);
$canImpersonate = $viewerPerms->check(Perm::U_CAN_IMPERSONATE);
$canSendTestMail = $currentUser->isSuperUser();
$hasAccess = $canManageUsers || $canManageNotes || $canManageWarnings || $canManageBans;

if(!$hasAccess)
    Template::throwError(403);

$notices = [];
$userId = (int)filter_input(INPUT_GET, 'u', FILTER_SANITIZE_NUMBER_INT);

try {
    $userInfo = $users->getUser($userId, 'id');
} catch(RuntimeException $ex) {
    Template::throwError(404);
}

$currentUserRank = $users->getUserRank($currentUser);
$userRank = $users->getUserRank($userInfo);

$canEdit = $canManageUsers && ($currentUser->isSuperUser() || (string)$currentUser->getId() === $userInfo->getId() || $currentUserRank > $userRank);
$canEditPerms = $canEdit && $canManagePerms;

$permsInfos = $perms->getPermissionInfo(userInfo: $userInfo, categoryNames: Perm::INFO_FOR_USER);
$permsLists = Perm::createList(Perm::LISTS_FOR_USER);
$permsNeedRecalc = false;

if(CSRF::validateRequest() && $canEdit) {
    if(!empty($_POST['impersonate_user'])) {
        if(!$canImpersonate) {
            $notices[] = 'You must be a super user to do this.';
        } elseif(!is_string($_POST['impersonate_user']) || $_POST['impersonate_user'] !== 'meow') {
            $notices[] = 'You didn\'t say the magic word.';
        } else {
            $allowToImpersonate = $currentUser->isSuperUser();

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

            if($allowToImpersonate) {
                $msz->createAuditLog('USER_IMPERSONATE', [$userInfo->getId(), $userInfo->getName()]);

                $tokenBuilder = $authInfo->getTokenInfo()->toBuilder();
                $tokenBuilder->setImpersonatedUserId($userInfo->getId());
                $tokenInfo = $tokenBuilder->toInfo();

                AuthTokenCookie::apply($tokenPacker->pack($tokenInfo));
                Tools::redirect($urls->format('index'));
                return;
            } else $notices[] = 'You aren\'t allowed to impersonate this user.';
        }
    }

    if(!empty($_POST['send_test_email'])) {
        if(!$canSendTestMail) {
            $notices[] = 'You must be a super user to do this.';
        } elseif(!is_string($_POST['send_test_email']) || $_POST['send_test_email'] !== 'yes_send_it') {
            $notices[] = 'Invalid request thing shut the fuck up.';
        } else {
            $testMail = Mailer::sendMessage(
                [$userInfo->getEMailAddress() => $userInfo->getName()],
                'Flashii Test E-mail',
                'You were sent this e-mail to validate if you can receive e-mails from Flashii. You may discard it.'
            );

            if(!$testMail)
                $notices[] = 'Failed to send test e-mail.';
        }
    }

    if(!empty($_POST['roles']) && is_array($_POST['roles'])) {
        // Read user input array and throw intval on em
        $applyRoles = [];
        foreach($_POST['roles'] as $item) {
            if(!ctype_digit($item))
                die('Invalid item encountered in roles list.');
            $applyRoles[] = (string)$item;
        }

        $existingRoles = [];
        foreach($roles->getRoles(userInfo: $userInfo) as $roleInfo)
            $existingRoles[$roleInfo->getId()] = $roleInfo;

        $removeRoles = [];

        foreach($existingRoles as $roleInfo) {
            if($roleInfo->isDefault() || !($currentUser->isSuperUser() || $userRank > $roleInfo->getRank()))
                continue;

            if(!in_array($roleInfo->getId(), $applyRoles))
                $removeRoles[] = $roleInfo;
        }

        if(!empty($removeRoles))
            $users->removeRoles($userInfo, $removeRoles);

        $addRoles = [];

        foreach($applyRoles as $roleId) {
            try {
                $roleInfo = $existingRoles[$roleId] ?? $roles->getRole($roleId);
            } catch(RuntimeException $ex) {
                continue;
            }

            if(!$currentUser->isSuperUser() && $userRank <= $roleInfo->getRank())
                continue;

            if(!in_array($roleInfo, $existingRoles))
                $addRoles[] = $roleInfo;
        }

        if(!empty($addRoles))
            $users->addRoles($userInfo, $addRoles);

        if(!empty($addRoles) || !empty($removeRoles))
            $permsNeedRecalc = true;
    }

    if(!empty($_POST['user']) && is_array($_POST['user'])) {
        $setCountry = (string)($_POST['user']['country'] ?? '');
        $setTitle = (string)($_POST['user']['title'] ?? '');

        $displayRole = (string)($_POST['user']['display_role'] ?? 0);
        if(!$users->hasRole($userInfo, $displayRole))
            $notices[] = 'User does not have the role you\'re trying to assign as primary.';

        $countryValidation = strlen($setCountry) === 2
            && ctype_alpha($setCountry)
            && ctype_upper($setCountry);

        if(!$countryValidation)
            $notices[] = 'Country code was invalid.';

        if(strlen($setTitle) > 64)
            $notices[] = 'User title was invalid.';

        if(empty($notices)) {
            $users->updateUser(
                userInfo: $userInfo,
                displayRoleInfo: $displayRole,
                countryCode: (string)($_POST['user']['country'] ?? 'XX'),
                title: (string)($_POST['user']['title'] ?? '')
            );
        }
    }

    if(!empty($_POST['colour']) && is_array($_POST['colour'])) {
        $setColour = null;

        if(!empty($_POST['colour']['enable'])) {
            $setColour = \Index\Colour\Colour::parse((string)($_POST['colour']['hex'] ?? ''));
            if($setColour->shouldInherit())
                $notices[] = 'Invalid colour specified.';
        }

        if(empty($notices))
            $users->updateUser(userInfo: $userInfo, colour: $setColour);
    }

    if(!empty($_POST['password']) && is_array($_POST['password'])) {
        $passwordNewValue = (string)($_POST['password']['new'] ?? '');
        $passwordConfirmValue = (string)($_POST['password']['confirm'] ?? '');

        if(!empty($passwordNewValue)) {
            if($passwordNewValue !== $passwordConfirmValue)
                $notices[] = 'Confirm password does not match.';
            else {
                $passwordValidation = $users->validatePassword($passwordNewValue);
                if($passwordValidation !== '')
                   $notices[] = $users->validatePasswordText($passwordValidation);
            }

            if(empty($notices))
                $users->updateUser(userInfo: $userInfo, password: $passwordNewValue);
        }
    }

    if($canEditPerms && filter_has_var(INPUT_POST, 'perms')) {
        $permsApply = Perm::convertSubmission(
            filter_input(INPUT_POST, 'perms', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY),
            Perm::INFO_FOR_USER
        );

        foreach($permsApply as $categoryName => $values)
            $perms->setPermissions($categoryName, $values['allow'], $values['deny'], userInfo: $userInfo);

        $permsNeedRecalc = true;
    }

    if($permsNeedRecalc)
        $perms->precalculatePermissions(
            $msz->getForumContext()->getCategories(),
            [$userInfo->getId()]
        );

    Tools::redirect($urls->format('manage-user', ['user' => $userInfo->getId()]));
    return;
}

$rolesAll = $roles->getRoles();
$userRoleIds = $users->hasRoles($userInfo, $rolesAll);

Template::render('manage.users.user', [
    'user_info' => $userInfo,
    'manage_notices' => $notices,
    'manage_roles' => $rolesAll,
    'manage_user_has_roles' => $userRoleIds,
    'can_edit_user' => $canEdit,
    'can_edit_perms' => $canEdit && $canEditPerms,
    'can_manage_notes' => $canManageNotes,
    'can_manage_warnings' => $canManageWarnings,
    'can_manage_bans' => $canManageBans,
    'can_impersonate' => $canImpersonate,
    'can_send_test_mail' => $canSendTestMail,
    'perms_lists' => $permsLists,
    'perms_infos' => $permsInfos,
]);
