<?php

namespace CleantalkSP\SpbctWP\UsersPassCheckModule;

use CleantalkSP\Common\TextPlate;
use CleantalkSP\SpbctWP\LinkConstructor;
use CleantalkSP\Variables\Post;
use PHP_CodeSniffer\Generators\Text;

class UsersPassCheckHandler
{
    /**
     * Add user pass
     *
     * @param object $user
     * @param string $username
     * @param string $password
     * @return object
     * @psalm-suppress PossiblyUnusedReturnValue, PossiblyUnusedParam
     */
    public static function addUserPass($user, $username, $password)
    {
        global $spbc;

        if ($spbc->settings['check_pass__enable'] == '0') {
            return $user;
        }

        if (is_wp_error($user)) {
            return $user;
        }

        if (empty($user->ID)) {
            return $user;
        }

        if (empty($password)) {
            return $user;
        }

        if (UsersPassCheckModel::isUserPassExists($user->ID)) {
            return $user;
        }

        if (!in_array($user->roles[0], $spbc->settings['check_pass__roles'])) {
            return $user;
        }

        UsersPassCheckModel::addUserPass($user->ID, strtoupper(sha1($password)));
        UsersPassCheckCron::handle();

        return $user;
    }

    /**
     * Remove user pass on password change
     *
     * Triggers only when a new password was actually submitted.
     * Supports WP core/admin field `pass1` and WooCommerce reset field `password_1`.
     *
     * @param int $user_id
     * @return void
     */
    public static function removeUserPassOnPasswordChange($user_id)
    {
        if (!self::isPasswordChangeSubmitted()) {
            return;
        }

        UsersPassCheckModel::removeUserPass($user_id);
    }

    /**
     * Whether the current request submits a new password.
     *
     * @return bool
     */
    private static function isPasswordChangeSubmitted()
    {
        // WP profile / reset form
        if (!empty($_POST['pass1'])) {
            return true;
        }

        // WooCommerce reset / account form
        if (!empty($_POST['password_1'])) {
            return true;
        }

        return false;
    }

    /**
     * Remove user pass on user delete
     *
     * @param int $user_id
     * @return void
     */
    public static function removeUserPassOnUserDelete($user_id)
    {
        UsersPassCheckModel::removeUserPass($user_id);
    }

    /**
     * Check pass leak
     *
     * @return void
     */
    public static function checkPassLeak()
    {
        spbc_check_ajax_referer('spbc_secret_nonce', 'security');

        global $spbc;

        if ($spbc->settings['check_pass__enable'] == '0') {
            wp_send_json_error(__('Password check is disabled', 'security-malware-firewall'));
        }

        $user_ids = Post::getArray('user_ids');

        if (empty($user_ids)) {
            wp_send_json_error(__('No user IDs provided', 'security-malware-firewall'));
        }

        if (!array_filter($user_ids, 'is_numeric')) {
            wp_send_json_error(__('User IDs must be numbers', 'security-malware-firewall'));
        }

        $users_pass = UsersPassCheckModel::getUsersPass($user_ids);

        $call_description = UserPassCheckView::callsDescriptionForUsersPage();

        $result = [];
        foreach ($user_ids as $user_id) {
            if (!isset($users_pass[$user_id])) {
                $result[$user_id]['text'] = __('Not verified', 'security-malware-firewall');
                $result[$user_id]['status'] = 'not_verified';
                continue;
            }

            $result[$user_id]['call_description'] = $call_description;

            $user_pass = $users_pass[$user_id];

            if ($user_pass->checked == 1 && $user_pass->leaked == 0) {
                $result[$user_id]['text'] = __('Checked and safe', 'security-malware-firewall');
                $result[$user_id]['status'] = 'safe';
                continue;
            }

            if ($user_pass->checked == 1 && $user_pass->leaked == 1) {
                $result[$user_id]['text'] = __('Leaked', 'security-malware-firewall');
                $result[$user_id]['status'] = 'leaked';
                $result[$user_id]['user_link'] = get_edit_user_link($user_id) . '#password';
                continue;
            }

            if ($user_pass->checked == 0) {
                $result[$user_id]['text'] = __('Awaiting check...', 'security-malware-firewall');
                $result[$user_id]['status'] = 'awaiting';
            }
        }

        wp_send_json_success($result);
    }

    /**
     * Get users with leaked passwords
     *
     * @return array
     */
    public static function getUsersWithLeakedPasswords()
    {
        $users_pass = UsersPassCheckModel::getUsersPass();
        $users_with_leaked_passwords = [];
        foreach ($users_pass as $user_id => $user_pass) {
            if ($user_pass->leaked == 1) {
                $users_with_leaked_passwords[$user_id] = $user_pass;
            }
        }
        return $users_with_leaked_passwords;
    }

    /**
     * Check pass leak for user
     *
     * @param string $pass_hash
     * @return bool|null
     */
    public static function isPassLeaked($pass_hash)
    {
        $http = new \CleantalkSP\Common\HTTP\Request();
        $result = $http
            ->setUrl('https://api.pwnedpasswords.com/range/' . substr($pass_hash, 0, 5))
            ->setData([])
            ->setPresets(['get'])
            ->request();

        if (!empty($result['error'])) {
            return null;
        }

        if (!is_string($result)) {
            return null;
        }

        $result = explode("\r\n", $result);

        foreach ($result as $line) {
            if (strpos($line, substr($pass_hash, 5)) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if user pass is leaked
     *
     * @param int $user_id
     * @return bool
     */
    public static function isUserPassLeaked($user_id)
    {
        global $spbc;

        if (!isset($spbc->settings['check_pass__enable']) || $spbc->settings['check_pass__enable'] == '0') {
            return false;
        }

        return UsersPassCheckModel::isUserPassLeaked($user_id);
    }
}
