<?php
/**
 * Handles the scheduling and sending of malware scan reports.
 *
 * @package WP_Defender\Model\Notification
 */

namespace WP_Defender\Model\Notification;

use DateTime;
use Exception;
use WP_Defender\Controller\Scan;
use WP_Defender\Model\Notification;
use WP_Defender\Model\Scan as Model_Scan;
use WP_Defender\Traits\Scan_Email_Template;

/**
 * Handles the scheduling and sending of malware scan reports.
 */
class Malware_Report extends Notification {

	use Scan_Email_Template;

	/**
	 * Table name.
	 *
	 * @var string
	 */
	protected $table = 'wd_malware_scanning_report';
	/**
	 * Slug identifier for the malware report.
	 *
	 * @var string
	 */
	public const SLUG = 'malware-report';

	/**
	 * Constructor method.
	 * Sets default values for the class.
	 */
	protected function before_load(): void {
		$default = array(
			'slug'                 => self::SLUG,
			'title'                => esc_html__( 'Malware Scanning - Reporting', 'defender-security' ),
			'status'               => self::STATUS_DISABLED,
			'description'          => esc_html__(
				'Automatically run regular scans of your website and email you reports.',
				'defender-security'
			),
			// @since 3.0.0 Fix 'Guest'-line.
			'in_house_recipients'  => is_user_logged_in() ? array( $this->get_default_user() ) : array(),
			'out_house_recipients' => array(),
			'type'                 => 'report',
			// @since 2.7.0 Add Scheduled Scanning to Malware settings.
			// Hide Schedule and 'dry_run' fields on UI but no delete for backward compatibility with Scan settings, the config structure and the Hub.
			'frequency'            => 'weekly',
			'day'                  => 'sunday',
			'day_n'                => '1',
			'time'                 => '4:00',
			'dry_run'              => false,
			'configs'              => array(
				'always_send' => false,
				'error_send'  => false,
				'template'    => $this->get_email_template(),
			),
		);
		$this->import( $default );
	}

	/**
	 * Checks if the "Scheduled Scan" is checked and sends the malware scan report if necessary.
	 *
	 * @return bool Returns true if the scan report should be sent, false otherwise.
	 */
	public function maybe_send(): bool {
		// @since 2.7.0 First, check "Scheduled Scan" is checked or not.
		if ( ! ( new \WP_Defender\Model\Setting\Scan() )->scheduled_scanning ) {
			return false;
		}

		if ( empty( $this->last_sent ) || empty( $this->est_timestamp ) ) {
			$this->last_sent     = $this->est_timestamp;
			$this->est_timestamp = $this->get_next_run()->getTimestamp();
			$this->save();
		}
		$time = apply_filters( 'defender_current_time_for_report', new DateTime( 'now', wp_timezone() ) );
		// Testing.
		if ( defined( 'WP_DEFENDER_TESTING' ) && true === constant( 'WP_DEFENDER_TESTING' ) ) {
			return true;
		}

		// Check by 'always_send' will be after scanning is complete.
		return $time->getTimestamp() >= $this->est_timestamp;
	}

	/**
	 * Sends the email.
	 * Retrieves data based on logic. Steps:
	 * 1) check the current active scan,
	 * 2) if there isn't active scan then check the latest scan,
	 * 3) save the report settings,
	 * 4) run new scan.
	 *
	 * @return void
	 * @throws Exception When an error occurs.
	 */
	public function send() {
		// The current status.
		$active = Model_Scan::get_active();
		if ( is_object( $active ) ) {
			// Scan is running.
			return;
		}
		// Check the latest scan.
		$model = Model_Scan::get_last();
		if ( ! is_object( $model ) ) {
			return;
		}
		// Save the report settings.
		$this->last_sent     = $this->est_timestamp;
		$this->est_timestamp = $this->get_next_run()->getTimestamp();
		$this->save();
		// Run scan.
		$scan = Model_Scan::create( true );
		if ( is_object( $scan ) && ! is_wp_error( $scan ) ) {
			$scan_controller = wd_di()->get( Scan::class );
			$scan_controller->do_async_scan( 'report' );
		}
	}

	/**
	 * Define settings labels.
	 *
	 * @return array
	 */
	public function labels(): array {
		return array(
			'report'             => esc_html__( 'Malware Scanning - Reporting', 'defender-security' ),
			'always_send'        => esc_html__( 'Send notifications when no issues are detected', 'defender-security' ),
			'report_subscribers' => esc_html__( 'Recipients', 'defender-security' ),
			'day'                => esc_html__( 'Day of', 'defender-security' ),
			'day_n'              => esc_html__( 'Day of', 'defender-security' ),
			'time'               => esc_html__( 'Time of day', 'defender-security' ),
			'frequency'          => esc_html__( 'Frequency', 'defender-security' ),
		);
	}

	/**
	 * Returns the next run date for the malware report in the format suitable for the Hub.
	 *
	 * @return string The formatted next run date for the malware report, or 'Never' if the report is not active.
	 */
	public function get_next_run_for_hub(): string {
		return self::STATUS_ACTIVE === $this->status
			? $this->persistent_hub_datetime_format( $this->est_timestamp )
			: esc_html__( 'Never', 'defender-security' );
	}

	/**
	 * Additional converting rules.
	 *
	 * @param  array $configs  The configuration data.
	 *
	 * @return array The type-casted configuration data.
	 * @since 3.1.0
	 */
	public function type_casting( $configs ): array {
		$configs['always_send'] = (bool) $configs['always_send'];
		$configs['error_send']  = (bool) $configs['error_send'];

		return $configs;
	}
}
