<?php

declare(strict_types=1);

namespace SecurWP\Modules\Reporting;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Email Digest - sends periodic summary emails of security activity.
 *
 * Supports daily, weekly, and monthly frequencies. Collects stats from the
 * audit log and scan results, then renders a branded HTML email.
 *
 */
class EmailDigest {

	private array $settings;

	/**
	 * Escape a plugin-owned table identifier for direct interpolation.
	 */
	private static function table_identifier( string $table ): string {
		if ( $table === '' || strlen( $table ) > 64 || ! preg_match( '/^[A-Za-z0-9_]+$/', $table ) ) {
			throw new \InvalidArgumentException( 'Invalid table identifier.' );
		}

		return '`' . str_replace( '`', '``', $table ) . '`';
	}

	public function __construct( array $settings ) {
		$this->settings = $settings;

		// Register custom cron schedules that WordPress does not ship with.
		add_filter( 'cron_schedules', [ $this, 'register_cron_schedules' ] );
	}

	/**
	 * Register weekly and monthly cron schedules.
	 *
	 * WordPress only provides 'hourly', 'twicedaily', and 'daily' out of the box.
	 *
	 * @param array $schedules Existing cron schedules.
	 * @return array Modified schedules.
	 */
	public function register_cron_schedules( array $schedules ): array {
		if ( ! isset( $schedules['weekly'] ) ) {
			$schedules['weekly'] = [
				'interval' => 604800,
				'display'  => 'Once Weekly',
			];
		}
		if ( ! isset( $schedules['monthly'] ) ) {
			$schedules['monthly'] = [
				'interval' => 2592000,
				'display'  => 'Once Monthly',
			];
		}
		return $schedules;
	}

	/**
	 * Send the periodic digest email.
	 * Hooked to securwp_email_digest cron.
	 */
	public function send_digest(): void {
		if ( empty( $this->settings['digest_enabled'] ) ) {
			return;
		}

		$recipient = $this->settings['digest_recipient'] ?? get_option( 'admin_email' );
		$period    = $this->settings['digest_frequency'] ?? 'weekly';

		$stats = $this->collect_stats( $period );

		$html    = $this->render_digest( $stats, $period );
		$subject = sprintf( '[SecurWP] %s Security Digest - %s', ucfirst( $period ), get_bloginfo( 'name' ) );

		add_filter( 'wp_mail_content_type', [ self::class, 'html_type' ] );
		wp_mail( $recipient, $subject, $html );
		remove_filter( 'wp_mail_content_type', [ self::class, 'html_type' ] );
	}

	public static function html_type(): string {
		return 'text/html';
	}

	private function collect_stats( string $period ): array {
		$now    = time();
		$ranges = [
			'daily'   => 86400,
			'weekly'  => 604800,
			'monthly' => 2592000,
		];
		$since  = $now - ( $ranges[ $period ] ?? 604800 );

		global $wpdb;
		$table = self::table_identifier( $wpdb->prefix . 'securwp_audit_log' );
		$table_name = trim( $table, '`' );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Checks existence of a plugin-owned audit table before collecting digest metrics.
		$table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) );

		$stats = [
			'period'          => $period,
			'since'           => $since,
			'until'           => $now,
			'total_events'    => 0,
			'firewall_blocks' => 0,
			'login_failures'  => 0,
			'scan_findings'   => 0,
			'user_changes'    => 0,
			'top_blocked_ips' => [],
		];

		if ( $table_exists ) {
			// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$stats['total_events'] = (int) $wpdb->get_var( $wpdb->prepare(
				"SELECT COUNT(*) FROM {$table} WHERE created_at >= %d",
				$since
			) );
			$stats['firewall_blocks'] = (int) $wpdb->get_var( $wpdb->prepare(
				"SELECT COUNT(*) FROM {$table} WHERE event = 'Firewall Block' AND created_at >= %d",
				$since
			) );
			$stats['login_failures'] = (int) $wpdb->get_var( $wpdb->prepare(
				"SELECT COUNT(*) FROM {$table} WHERE event = 'Login Failed' AND created_at >= %d",
				$since
			) );
			// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		}

		$published_id = \SecurWP\Includes\SettingsStore::get_field( \SecurWP\Includes\SettingsStore::COL_STATE, 'published_scan_id', null );
		if ( $published_id && class_exists( '\SecurWP\Modules\Scanner\Repository\IssueRepository' ) ) {
			$counts                 = \SecurWP\Modules\Scanner\Repository\IssueRepository::getCounts();
			$stats['scan_findings'] = $counts['active'] ?? 0;
		}

		return $stats;
	}

	private function render_digest( array $stats, string $period ): string {
		$site         = get_bloginfo( 'name' );
		$period_label = ucfirst( $period );
		$date_range   = gmdate( 'M j', $stats['since'] ) . ' - ' . gmdate( 'M j', $stats['until'] );

		$html  = '<!DOCTYPE html><html><head><meta charset="utf-8"></head>';
		$html .= '<body style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px;">';
		$html .= '<h2 style="color:#1e40af;">' . esc_html( $site ) . ' - ' . esc_html( $period_label ) . ' Security Digest</h2>';
		$html .= '<p style="color:#6b7280;">' . esc_html( $date_range ) . '</p>';
		$html .= '<table style="width:100%;border-collapse:collapse;margin:20px 0;">';
		$html .= '<tr><td style="padding:12px;border-bottom:1px solid #e5e7eb;font-weight:bold;">Total Events</td>';
		$html .= '<td style="padding:12px;border-bottom:1px solid #e5e7eb;text-align:right;">' . (int) $stats['total_events'] . '</td></tr>';
		$html .= '<tr><td style="padding:12px;border-bottom:1px solid #e5e7eb;font-weight:bold;">Firewall Blocks</td>';
		$html .= '<td style="padding:12px;border-bottom:1px solid #e5e7eb;text-align:right;">' . (int) $stats['firewall_blocks'] . '</td></tr>';
		$html .= '<tr><td style="padding:12px;border-bottom:1px solid #e5e7eb;font-weight:bold;">Failed Logins</td>';
		$html .= '<td style="padding:12px;border-bottom:1px solid #e5e7eb;text-align:right;">' . (int) $stats['login_failures'] . '</td></tr>';
		$html .= '<tr><td style="padding:12px;border-bottom:1px solid #e5e7eb;font-weight:bold;">Active Scan Findings</td>';
		$html .= '<td style="padding:12px;border-bottom:1px solid #e5e7eb;text-align:right;">' . (int) $stats['scan_findings'] . '</td></tr>';
		$html .= '</table>';
		$html .= '<p style="color:#6b7280;font-size:12px;">Generated by SecurWP</p>';
		$html .= '</body></html>';

		return $html;
	}

	public function schedule_digest(): void {
		$hook = 'securwp_email_digest';

		if ( empty( $this->settings['digest_enabled'] ) ) {
			wp_clear_scheduled_hook( $hook );
			return;
		}

		$frequency  = $this->settings['digest_frequency'] ?? 'weekly';
		$recurrence = $frequency === 'daily' ? 'daily' : ( $frequency === 'monthly' ? 'monthly' : 'weekly' );

		// Only reschedule if the event is not already scheduled with the correct recurrence.
		$next = wp_next_scheduled( $hook );
		if ( $next ) {
			$existing_schedule = wp_get_schedule( $hook );
			if ( $existing_schedule === $recurrence ) {
				// Already scheduled with the correct frequency - no changes needed.
				return;
			}
			// Frequency changed: clear old schedule and set the new one.
			wp_clear_scheduled_hook( $hook );
		}

		wp_schedule_event( time(), $recurrence, $hook );
	}
}
