<?php

namespace CleantalkSP\SpbctWP\UsersPassCheckModule;

class UsersPassCheckModel
{
    /**
     * Add user pass
     *
     * @param int $user_id
     * @param string $pass_hash
     * @return int|false
     * @psalm-suppress PossiblyUnusedReturnValue
     */
    public static function addUserPass($user_id, $pass_hash)
    {
        global $wpdb;

        return $wpdb->insert(
            $wpdb->base_prefix . 'spbc_users_pass',
            array(
                'user_id' => $user_id,
                'pass_hash' => $pass_hash,
            ),
            array(
                '%d',
                '%s',
            )
        );
    }

    /**
     * Check if user pass exists
     *
     * @param int $user_id
     * @return bool
     */
    public static function isUserPassExists($user_id)
    {
        global $wpdb;

        $count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE user_id = %d",
                $user_id
            )
        );

        return $count > 0;
    }

    /**
     * Check if user pass must be checked
     *
     * @return bool
     */
    public static function isUserPassMustBeChecked()
    {
        global $wpdb;

        $count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE checked = 0"
        );

        return $count > 0;
    }

    /**
     * Remove user pass
     *
     * @param int $user_id
     * @return void
     */
    public static function removeUserPass($user_id)
    {
        global $wpdb;

        $wpdb->delete(
            $wpdb->base_prefix . 'spbc_users_pass',
            array(
                'user_id' => $user_id,
            ),
            array(
                '%d',
            )
        );
    }

    /**
     * Get users pass
     *
     * @param array $user_ids
     * @return array
     */
    public static function getUsersPass($user_ids = [])
    {
        global $wpdb;

        if (!empty($user_ids)) {
            $user_ids = array_map('intval', $user_ids);
            $placeholders = implode(',', array_fill(0, count($user_ids), '%d'));

            $sql = $wpdb->prepare(
                "SELECT user_id, checked, leaked FROM {$wpdb->base_prefix}spbc_users_pass WHERE user_id IN ({$placeholders})",
                ...$user_ids
            );
            $users_pass = $wpdb->get_results($sql);

            $result = [];
            foreach ($users_pass as $user_pass) {
                $result[$user_pass->user_id] = $user_pass;
            }

            return $result;
        }

        $users_pass = $wpdb->get_results("SELECT user_id, checked, leaked FROM {$wpdb->base_prefix}spbc_users_pass");
        $result = [];
        foreach ($users_pass as $user_pass) {
            $result[$user_pass->user_id] = $user_pass;
        }

        return $result;
    }

    /**
     * Get users that must be checked
     *
     * @param int $iteration
     * @return array
     */
    public static function getUsersThatMustBeChecked($iteration = 10)
    {
        global $wpdb;

        $users = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT user_id, pass_hash FROM {$wpdb->base_prefix}spbc_users_pass WHERE checked = 0 LIMIT %d",
                $iteration
            )
        );

        $users_ids = [];
        foreach ($users as $user) {
            $users_ids[$user->user_id] = $user->pass_hash;
        }

        return $users_ids;
    }

    /**
     * Mark users as checked
     *
     * @param array $user_ids
     * @return void
     */
    public static function markUsersAsChecked($user_ids)
    {
        global $wpdb;

        $user_ids_placeholders = implode(',', array_fill(0, count($user_ids), '%d'));
        $query = "UPDATE {$wpdb->base_prefix}spbc_users_pass SET checked = 1 WHERE user_id IN ($user_ids_placeholders)";
        $wpdb->query(
            $wpdb->prepare(
                $query,
                $user_ids
            )
        );
    }

    /**
     * Mark users as leaked
     *
     * @param array $user_ids
     * @return void
     */
    public static function markUsersAsLeaked($user_ids)
    {
        global $wpdb;

        $leaked_user_ids = [];
        foreach ($user_ids as $user_id => $user_data) {
            if ($user_data['leaked'] == 1) {
                $leaked_user_ids[] = $user_id;
            }
        }

        if (!empty($leaked_user_ids)) {
            $leaked_user_ids_placeholders = implode(',', array_fill(0, count($leaked_user_ids), '%d'));
            $query = "UPDATE {$wpdb->base_prefix}spbc_users_pass SET leaked = 1 WHERE user_id IN ($leaked_user_ids_placeholders)";
            $wpdb->query(
                $wpdb->prepare(
                    $query,
                    $leaked_user_ids
                )
            );
        }
    }

    /**
     * Get total users checked
     *
     * @return int|null
     */
    public static function getTotalUsersChecked()
    {
        global $wpdb;

        $count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE checked = 1"
        );

        if (is_null($count)) {
            return 0;
        }

        return (int) $count;
    }

    /**
     * Get safe passwords count
     *
     * @return int
     */
    public static function getSafePasswordsCount()
    {
        global $wpdb;

        $count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE leaked = 0 AND checked = 1"
        );

        return (int) $count;
    }

    /**
     * Get compromised passwords count
     *
     * @return int
     */
    public static function getCompromisedPasswordsCount()
    {
        global $wpdb;

        $count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE leaked = 1 AND checked = 1"
        );

        return (int) $count;
    }

    /**
     * Get pending checks count
     *
     * @return int
     */
    public static function getPendingChecksCount()
    {
        global $wpdb;

        $count = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->base_prefix}spbc_users_pass WHERE checked = 0"
        );

        return (int) $count;
    }

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

        $user_pass = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT leaked FROM {$wpdb->base_prefix}spbc_users_pass WHERE user_id = %d",
                $user_id
            )
        );

        if (is_null($user_pass)) {
            return false;
        }

        return $user_pass->leaked == 1;
    }

    /**
     * Hook. Untrack user if role is disabled after settings saved.
     * @param array $settings
     * @return array
     * @psalm-suppress PossiblyUnusedReturnValue
     */
    public static function hookUntrackUsers($settings)
    {
        global $wpdb;

        if (empty($settings) || empty($settings['check_pass__enable'])) {
            return $settings;
        }
        $roles = empty($settings['check_pass__roles']) ? array() : $settings['check_pass__roles'];

        $users = $wpdb->get_results(
            "SELECT id, user_id FROM {$wpdb->base_prefix}spbc_users_pass"
        );

        $to_remove = array();
        foreach ($users as $user) {
            if (
                !spbc_is_user_role_in(
                    $roles,
                    get_user_by('id', $user->user_id)
                )
            ) {
                $to_remove[] = $user->id;
            }
        }
        if (!empty($to_remove)) {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$wpdb->base_prefix}spbc_users_pass WHERE id IN (%s)",
                    implode(',', $to_remove)
                )
            );
        }
        return $settings;
    }
}
