<?php
namespace Misuzu;

use RuntimeException;
use Index\Colour\Colour;
use Misuzu\Users\User;
use Misuzu\Users\UserRole;

if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_USER, User::getCurrent()->getId(), MSZ_PERM_USER_MANAGE_USERS)) {
    echo render_error(403);
    return;
}

$notices = [];
$userId = (int)filter_input(INPUT_GET, 'u', FILTER_SANITIZE_NUMBER_INT);
$currentUser = User::getCurrent();
$currentUserId = $currentUser->getId();

try {
    $userInfo = User::byId($userId);
} catch(RuntimeException $ex) {
    echo render_error(404);
    return;
}

$canEdit = $currentUser->hasAuthorityOver($userInfo);
$canEditPerms = $canEdit && perms_check_user(MSZ_PERMS_USER, $currentUserId, MSZ_PERM_USER_MANAGE_PERMS);
$permissions = manage_perms_list(perms_get_user_raw($userId));

if(CSRF::validateRequest() && $canEdit) {
    if(!empty($_POST['impersonate_user'])) {
        if(!$currentUser->isSuper()) {
            $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 {
            $authToken->setImpersonatedUserId($userInfo->getId());
            $authToken->applyCookie();
            url_redirect('index');
            return;
        }
    }

    if(!empty($_POST['send_test_email'])) {
        if(!$currentUser->isSuper()) {
            $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->getUsername()],
                '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[] = (int)$item;
        }

        // Fetch existing roles
        $existingRoles = $userInfo->getRoles();

        // Initialise set array with existing roles
        $setRoles = $existingRoles;

        // Storage array for roles to dump
        $removeRoles = [];

        // STEP 1: Check for roles to be removed in the existing set.
        //         Roles that the current users isn't allowed to touch (hierarchy) will stay.
        foreach($setRoles as $role) {
            // Also prevent the main role from being removed.
            if($role->isDefault() || !$currentUser->hasAuthorityOver($role))
                continue;
            if(!in_array($role->getId(), $applyRoles))
                $removeRoles[] = $role;
        }

        // STEP 2: Purge the ones marked for removal.
        $setRoles = array_diff($setRoles, $removeRoles);

        // STEP 3: Add roles to the set array from the user input, if the user has authority over the given roles.
        foreach($applyRoles as $roleId) {
            try {
                $role = $existingRoles[$roleId] ?? UserRole::byId($roleId);
            } catch(RuntimeException $ex) {
                continue;
            }
            if(!$currentUser->hasAuthorityOver($role))
                continue;
            if(!in_array($role, $setRoles))
                $setRoles[] = $role;
        }

        foreach($removeRoles as $role)
            $userInfo->removeRole($role);

        foreach($setRoles as $role)
            $userInfo->addRole($role);
    }

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

        $displayRole = (int)($_POST['user']['display_role'] ?? 0);

        try {
            $userInfo->setDisplayRole(UserRole::byId($displayRole));
        } catch(RuntimeException $ex) {}

        $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))
            $userInfo->setCountry((string)($_POST['user']['country'] ?? ''))
                ->setTitle((string)($_POST['user']['title'] ?? ''))
                ->setDisplayRole(UserRole::byId((int)($_POST['user']['display_role'] ?? 0)));
    }

    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))
            $userInfo->setColour($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.';
            elseif(!empty(User::validatePassword($passwordNewValue)))
                $notices[] = 'New password is too weak.';
            else
                $userInfo->setPassword($passwordNewValue);
        }
    }

    if(empty($notices))
        $userInfo->save();

    if($canEditPerms && !empty($_POST['perms']) && is_array($_POST['perms'])) {
        $perms = manage_perms_apply($permissions, $_POST['perms']);

        if($perms !== null) {
            if(!perms_set_user_raw($userId, $perms))
                $notices[] = 'Failed to update permissions.';
        } else {
            if(!perms_delete_user($userId))
                $notices[] = 'Failed to remove permissions.';
        }

        // this smells, make it refresh/apply in a non-retarded way
        $permissions = manage_perms_list(perms_get_user_raw($userId));
    }
}

Template::render('manage.users.user', [
    'user_info' => $userInfo,
    'manage_notices' => $notices,
    'manage_roles' => UserRole::all(true),
    'can_edit_user' => $canEdit,
    'can_edit_perms' => $canEdit && $canEditPerms,
    'permissions' => $permissions ?? [],
]);
