<?php
/**
 * Activity Intelligence.
 *
 * Adds observability on top of the Activity Log (no second event store):
 *   - Anomaly detection: a daily job baselines each action type and alerts on
 *     statistical spikes/drops (e.g. a surge in trashed posts) via a dashboard
 *     notice and, for critical findings, an email.
 *
 * (The Staff Activity Report is registered here too once added.)
 *
 * Works best with the Activity Log module enabled and collecting events.
 * Default off.
 *
 * SECURITY: admin-only notice + capability-checked, nonce-protected dismiss.
 *
 * @package Platform\Helm\Modules\Activity_Intelligence
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Activity_Intelligence;

use Platform\Helm\Contracts\ModuleInterface;

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

final class ActivityIntelligenceModule implements ModuleInterface {

	public const SCAN_CRON_HOOK = 'platform_helm_anomaly_scan';

	private const ANOMALY_OPTION  = 'platform_helm_anomalies';
	private const DISMISS_ACTION  = 'platform_helm_anomaly_dismiss';
	private const SHOW_DAYS       = 7;

	/* ===================================================================== *
	 * ModuleInterface
	 * ===================================================================== */

	public function id(): string {
		return 'activity_intelligence';
	}

	public function name(): string {
		return __( 'Activity Intelligence', 'platform-helm' );
	}

	public function description(): string {
		return __( 'Watches your Activity Log for unusual spikes or drops — like a surge in deletions or a collapse in publishing — and alerts you with a notice (and an email for critical findings). Works best with the Activity Log enabled.', 'platform-helm' );
	}

	public function default_enabled(): bool {
		return false;
	}

	public function boot(): void {
		if ( ! wp_next_scheduled( self::SCAN_CRON_HOOK ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', self::SCAN_CRON_HOOK );
		}
		add_action( self::SCAN_CRON_HOOK, [ $this, 'run_scan' ] );
		add_action( 'admin_notices', [ $this, 'maybe_notice' ] );
		add_action( 'admin_post_' . self::DISMISS_ACTION, [ $this, 'handle_dismiss' ] );

		// Staff Activity Report admin page.
		( new StaffReportPage() )->register_hooks();
	}

	/** Clear the cron — called from Plugin::on_deactivate(). */
	public static function unschedule(): void {
		$ts = wp_next_scheduled( self::SCAN_CRON_HOOK );
		if ( $ts ) {
			wp_unschedule_event( $ts, self::SCAN_CRON_HOOK );
		}
		wp_clear_scheduled_hook( self::SCAN_CRON_HOOK );
	}

	/* ===================================================================== *
	 * SCAN
	 * ===================================================================== */

	/**
	 * Run a detection pass, store the result, and email on critical findings.
	 * Public so it can be triggered on demand (cron, tools, tests).
	 */
	public function run_scan(): void {
		$items = ( new AnomalyDetector() )->detect();

		update_option(
			self::ANOMALY_OPTION,
			[
				'detected_at' => time(),
				'items'       => $items,
			],
			false
		);

		$critical = array_values( array_filter( $items, static fn( $a ) => 'critical' === ( $a['severity'] ?? '' ) ) );
		/** Filter: allow disabling the critical-anomaly email. */
		if ( ! empty( $critical ) && apply_filters( 'platform_helm_anomaly_email', true ) ) {
			$this->email_alert( $critical );
		}
	}

	/* ===================================================================== *
	 * ALERTING
	 * ===================================================================== */

	public function maybe_notice(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		$data  = get_option( self::ANOMALY_OPTION, [] );
		$items = is_array( $data ) && isset( $data['items'] ) && is_array( $data['items'] ) ? $data['items'] : [];
		$when  = is_array( $data ) ? (int) ( $data['detected_at'] ?? 0 ) : 0;
		if ( empty( $items ) || $when < ( time() - self::SHOW_DAYS * DAY_IN_SECONDS ) ) {
			return;
		}

		$dismiss = wp_nonce_url( admin_url( 'admin-post.php?action=' . self::DISMISS_ACTION ), self::DISMISS_ACTION );

		echo '<div class="notice notice-warning is-dismissible"><p><strong>' . esc_html__( 'Platform Helm — activity anomalies detected', 'platform-helm' ) . '</strong></p><ul style="list-style:disc;margin-left:20px">';
		foreach ( array_slice( $items, 0, 5 ) as $a ) {
			echo '<li>' . esc_html( $this->describe( (array) $a ) ) . '</li>';
		}
		echo '</ul><p><a href="' . esc_url( $dismiss ) . '">' . esc_html__( 'Dismiss', 'platform-helm' ) . '</a> &nbsp;·&nbsp; <a href="' . esc_url( admin_url( 'admin.php?page=platform-helm-activity-log' ) ) . '">' . esc_html__( 'Open Activity Log', 'platform-helm' ) . '</a></p></div>';
	}

	public function handle_dismiss(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Permission denied.', 'platform-helm' ), '', [ 'response' => 403 ] );
		}
		check_admin_referer( self::DISMISS_ACTION );
		delete_option( self::ANOMALY_OPTION );
		wp_safe_redirect( wp_get_referer() ?: admin_url() );
		exit;
	}

	/** @param array<string,mixed> $a */
	private function describe( array $a ): string {
		$icon = 'critical' === ( $a['severity'] ?? '' ) ? '🔴' : '🟠';
		return sprintf(
			/* translators: 1: marker, 2: direction, 3: label, 4: count, 5: average, 6: z-score */
			__( '%1$s %2$s in %3$s — %4$s vs ~%5$s/day average (Z=%6$s)', 'platform-helm' ),
			$icon,
			ucfirst( (string) ( $a['direction'] ?? '' ) ),
			(string) ( $a['label'] ?? '' ),
			number_format_i18n( (int) ( $a['count'] ?? 0 ) ),
			number_format_i18n( (float) ( $a['mean'] ?? 0 ), 1 ),
			number_format_i18n( (float) ( $a['z'] ?? 0 ), 1 )
		);
	}

	/** @param array<int,array<string,mixed>> $critical */
	private function email_alert( array $critical ): void {
		$to = (string) get_option( 'admin_email' );
		if ( '' === $to ) {
			return;
		}
		$site    = wp_specialchars_decode( (string) get_bloginfo( 'name' ), ENT_QUOTES );
		$subject = sprintf( /* translators: %s: site name */ __( '[%s] Platform Helm: activity anomaly detected', 'platform-helm' ), $site );

		$lines = [ __( 'Platform Helm detected unusual activity on your site:', 'platform-helm' ), '' ];
		foreach ( $critical as $a ) {
			$lines[] = '• ' . $this->describe( (array) $a );
		}
		$lines[] = '';
		$lines[] = __( 'Review:', 'platform-helm' ) . ' ' . admin_url( 'admin.php?page=platform-helm-activity-log' );

		wp_mail( $to, $subject, implode( "\n", $lines ) );
	}
}
