<?php

namespace CleantalkSP\SpbctWP\UsersPassCheckModule;

use CleantalkSP\SpbctWP\Cron as SpbcCron;

class UsersPassCheckCron
{
    /**
     * Cron job name
     *
     * @var string
     */
    const CRON_JOB_WORKER_NAME = 'users_pass_check_worker';

    /**
     * Cron job period
     *
     * @var int
     */
    const CRON_JOB_WORKER_PERIOD = 600; // 10 minutes

    /**
     * Cron job iteration for get users that must be checked
     *
     * @var int
     */
    const CRON_JOB_USERS_PASS_CHECK_ITERATION = 10;

    /**
     * Handle cron job
     * check if exists users with checked = 0
     * if exists, set cron job in 10 minutes
     *
     * @return void
     */
    public static function handle()
    {
        if (UsersPassCheckModel::isUserPassMustBeChecked()) {
            SpbcCron::updateTask(self::CRON_JOB_WORKER_NAME, 'spbc_cron__users_pass_check_worker', self::CRON_JOB_WORKER_PERIOD);
        }
    }

    /**
     * This is the Cron handler for the `spbc_cron__users_pass_check_worker` task
     *
     * @return void
     */
    public static function worker()
    {
        global $spbc;
        $users_ids = UsersPassCheckModel::getUsersThatMustBeChecked(self::CRON_JOB_USERS_PASS_CHECK_ITERATION);
        if (empty($users_ids)) {
            SpbcCron::removeTask(self::CRON_JOB_WORKER_NAME);
            return;
        }

        // check that https://api.pwnedpasswords.com/range/ is available
        $http = new \CleantalkSP\Common\HTTP\Request();
        $result = $http
            ->setUrl('https://api.pwnedpasswords.com/range/')
            ->setData([])
            ->setPresets(['get_code', 'get'])
            ->request();

        $spbc->data['user_pass_checker_last_request'] = current_time('timestamp');
        $spbc->save('data');

        if (!empty($result['error'])) {
            SpbcCron::removeTask(self::CRON_JOB_WORKER_NAME);
            return;
        }

        if ($result != 400) {
            SpbcCron::removeTask(self::CRON_JOB_WORKER_NAME);
            return;
        }

        $result = [];
        $is_api_available = true;
        foreach ($users_ids as $user_id => $pass_hash) {
            $is_leaked = UsersPassCheckHandler::isPassLeaked($pass_hash);
            if (is_null($is_leaked)) {
                $is_api_available = false;
                break;
            }
            $result[$user_id]['leaked'] = $is_leaked ? 1 : 0;
        }

        if (!empty($result)) {
            UsersPassCheckModel::markUsersAsChecked(array_keys($result));
            UsersPassCheckModel::markUsersAsLeaked($result);
        }

        if (!$is_api_available || !UsersPassCheckModel::isUserPassMustBeChecked()) {
            SpbcCron::removeTask(self::CRON_JOB_WORKER_NAME);
        }
    }

    /**
     * Get last check time
     *
     * @return null|int
     */
    public static function getLastCheckTime()
    {
        global $spbc;
        $last_request_ts = $spbc->data['user_pass_checker_last_request'];

        return empty($last_request_ts) ? null : (int)$last_request_ts;
    }

    /**
     * Get next check time
     *
     * @return null|int
     */
    public static function getNextCheckTime()
    {
        $next_call_final_ts = null;
        $next_call_worker = SpbcCron::getTask(self::CRON_JOB_WORKER_NAME);
        $next_call_routine = SpbcCron::getTask('users_pass_check_routine');

        if (isset($next_call_worker['next_call'], $next_call_routine['next_call'])) {
            $next_call_final_ts = min((int)$next_call_worker['next_call'], (int)$next_call_routine['next_call']);
        } else {
            if (isset($next_call_worker['next_call'])) {
                $next_call_final_ts = $next_call_worker['next_call'];
            } else if (isset($next_call_routine['next_call'])) {
                $next_call_final_ts = $next_call_routine['next_call'];
            }
        }

        return empty($next_call_final_ts) ? null : (int)$next_call_final_ts;
    }
}
