<?php

use iThemesSecurity\Site_Scanner\Issue;
use iThemesSecurity\Site_Scanner\Scan;
use iThemesSecurity\Site_Scanner\Vulnerability_Issue;

class ITSEC_Malware_Scheduling_Scanner {

	/**
	 * Perform the scheduled scan and send an email summarizing the results.
	 *
	 * @param int $site_id
	 *
	 * @return Scan
	 */
	public static function scan( $site_id = 0 ) {
		$previous_vulnerabilities = ITSEC_Modules::get_setting( 'site-scanner', 'vulnerabilities' );

		$scan = ITSEC_Site_Scanner_API::scan( $site_id );

		if ( $scan->is_error() ) {
			if ( $scan->get_error()->get_error_message( 'itsec-temporary-server-error' ) ) {
				return $scan;
			}

			if ( $scan->get_error()->get_error_message( 'rate_limit_exceeded' ) ) {
				return $scan;
			}
		}

		if ( ITSEC_Lib_Remote_Messages::has_action( 'malware-scanner-disable-malware-warnings' ) ) {
			return $scan;
		}

		self::send_email( self::prepare_scan_for_notification( $scan, $previous_vulnerabilities ) );

		return $scan;
	}

	/**
	 * We should not notify about all issues. So we remove several types of issues here:
	 * - with priority less than defined in "Notification threshold" setting (medium by default, can be set up by the user)
	 * - issues were found (and reported) within the previous scan
	 *
	 * @psalm-param list<array{
	 *     type: string,
	 *     software: array,
	 *     issues: array,
	 *     link: string
	 * }> $previous_vulnerabilities
	 * @param Scan $scan
	 * @param array $previous_vulnerabilities
	 *
	 * @return Scan
	 */
	private static function prepare_scan_for_notification( Scan $scan, array $previous_vulnerabilities ): Scan {
		$threshold = ITSEC_Modules::get_setting('malware-scheduling', 'notification_threshold');

		$links = [];
		foreach ($previous_vulnerabilities as $vulnerability) {
			$links[$vulnerability['link']] = $vulnerability['link'];
		}

		return $scan->filter_issues( function ( Issue $issue ) use ( $links, $threshold ) {
			if ($issue->get_priority() < $threshold) {
				return false;
			}

			if ( ! $issue instanceof Vulnerability_Issue ) {
				// We want to filter only previous vulnerabilities
				return true;
			}

			return ! isset( $links[ $issue->get_link() ] );
		});
	}

	/**
	 * Get the next site ID to scan based on the current site ID.
	 *
	 * @param int $site_id
	 *
	 * @return int|null
	 */
	public static function get_next_site_id( $site_id ) {

		global $wpdb;

		$id = $wpdb->get_var( $wpdb->prepare( "SELECT `blog_id` FROM {$wpdb->blogs} WHERE `public` = 1 AND `archived` = 0 AND `deleted` = 0 AND `blog_id` > %d ORDER BY `blog_id` ASC LIMIT 1", $site_id ) );

		if ( null === $id ) {
			return null;
		}

		if ( is_main_site( $id ) ) {
			return static::get_next_site_id( $id );
		}

		return (int) $id;
	}

	/**
	 * Sends an email with the scan results.
	 *
	 * @param Scan $scan
	 */
	public static function send_email( $scan ) {

		$nc = ITSEC_Core::get_notification_center();

		if ( ! $nc->is_notification_enabled( 'malware-scheduling' ) ) {
			return;
		}

		ITSEC_Site_Scanner_Mail::send( $scan );
	}
}
