<?php
/**
 * Email Health configuration diagnostics.
 *
 * @package SubmissionInbox
 */

namespace SUBIN\Mail;

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

/**
 * Builds deterministic, non-network Email Health checks and support context.
 */
class EmailHealthDiagnosticService {
	/** @var \SUBIN_SettingsRepository */
	private $settings;

	/** @var EmailHealthService */
	private $health;

	/** @var EmailVerificationService */
	private $verification;

	/** Constructor. */
	public function __construct( \SUBIN_SettingsRepository $settings, ?EmailHealthService $health = null, ?EmailVerificationService $verification = null ) {
		$this->settings     = $settings;
		$this->health       = $health ? $health : new EmailHealthService();
		$this->verification = $verification ? $verification : new EmailVerificationService( $settings );
	}

	/**
	 * Return checks that are safe to run during an admin page request.
	 *
	 * No DNS, SMTP socket, or loopback request is performed here.
	 *
	 * @return array<int,array<string,string>>
	 */
	public function checks() {
		return array(
			$this->transport_check(),
			$this->sender_check(),
			$this->cron_check(),
			$this->logging_check(),
		);
	}

	/**
	 * Build a redacted support report.
	 *
	 * @param array<string,mixed>                 $health_report Current scoped Health report.
	 * @param array<int,array<string,string>>|null $checks Optional prebuilt checks.
	 * @return string
	 */
	public function support_report( array $health_report, ?array $checks = null ) {
		$checks       = null === $checks ? $this->checks() : $checks;
		$verification = $this->verification->last_result();
		$summary      = (array) ( $health_report['summary'] ?? array() );
		$lines        = array(
			'InboxMend Email Health support report',
			'Generated (UTC): ' . gmdate( 'Y-m-d H:i:s' ),
			'InboxMend version: ' . ( defined( 'SUBIN_PLUGIN_VERSION' ) ? SUBIN_PLUGIN_VERSION : 'unknown' ),
			'WordPress version: ' . sanitize_text_field( (string) get_bloginfo( 'version' ) ),
			'PHP version: ' . PHP_VERSION,
			'Multisite: ' . ( is_multisite() ? 'yes' : 'no' ),
			'Health lifecycle state: ' . sanitize_key( $health_report['state'] ?? 'unknown' ),
			'Events in selected activity view: ' . absint( $summary['total'] ?? 0 ),
			'Accepted / failed / missing / unknown: ' . implode( ' / ', array_map( 'absint', array( $summary['sent'] ?? 0, $summary['failed'] ?? 0, $summary['no_email_generated'] ?? 0, $summary['unknown'] ?? 0 ) ) ),
		);

		foreach ( $checks as $check ) {
			$lines[] = sprintf( 'Check %s: %s', sanitize_key( $check['key'] ?? 'unknown' ), sanitize_key( $check['status'] ?? 'unknown' ) );
		}

		if ( $verification ) {
			$lines[] = 'Last verification: ' . sanitize_key( $verification['status'] ?? 'unknown' ) . ' at ' . sanitize_text_field( $verification['tested_at_gmt'] ?? '' ) . ' UTC';
			$lines[] = 'Mailbox confirmation: ' . sanitize_key( $verification['confirmation'] ?? 'not_applicable' );
			if ( ! empty( $verification['confirmed_at_gmt'] ) ) {
				$lines[] = 'Mailbox confirmation recorded: ' . sanitize_text_field( $verification['confirmed_at_gmt'] ) . ' UTC';
			}
			if ( ! empty( $verification['issue_code'] ) ) {
				$lines[] = 'Verification issue: ' . sanitize_key( $verification['issue_code'] );
			}
		} else {
			$lines[] = 'Last verification: never';
		}

		return implode( "\n", $lines );
	}

	/** Transport configuration check. */
	private function transport_check() {
		$settings = $this->settings->all();
		if ( empty( $settings['enable_smtp'] ) ) {
			return $this->check( 'transport', 'info', __( 'WordPress default mail method', 'submission-inbox' ), __( 'SMTP is not enabled in InboxMend. WordPress will use the host’s default mail method.', 'submission-inbox' ), 'settings_sending' );
		}

		if ( '' === trim( (string) ( $settings['smtp_host'] ?? '' ) ) ) {
			return $this->check( 'transport', 'fail', __( 'SMTP configuration is incomplete', 'submission-inbox' ), __( 'SMTP is enabled, but the server host is missing.', 'submission-inbox' ), 'settings_sending' );
		}

		if ( ! empty( $settings['smtp_auth'] ) && ( '' === trim( (string) ( $settings['smtp_username'] ?? '' ) ) || '' === (string) ( $settings['smtp_password'] ?? '' ) ) ) {
			return $this->check( 'transport', 'fail', __( 'SMTP credentials are incomplete', 'submission-inbox' ), __( 'SMTP authentication is enabled, but a username or password is missing.', 'submission-inbox' ), 'settings_sending' );
		}

		if ( 'none' === ( $settings['smtp_encryption'] ?? '' ) ) {
			return $this->check( 'transport', 'warning', __( 'SMTP has no configured encryption', 'submission-inbox' ), __( 'The SMTP server is configured, but the connection is not set to TLS or SSL.', 'submission-inbox' ), 'settings_sending' );
		}

		return $this->check( 'transport', 'pass', __( 'SMTP configuration is complete', 'submission-inbox' ), __( 'Host, port, authentication, and encryption have values. Run a verification email to test the connection.', 'submission-inbox' ), 'verify' );
	}

	/** Sender address and domain alignment check. */
	private function sender_check() {
		$settings = $this->settings->all();
		$from     = sanitize_email( (string) ( $settings['from_email'] ?? '' ) );
		if ( '' === $from ) {
			$from = sanitize_email( (string) get_option( 'admin_email' ) );
		}
		if ( '' === $from || ! is_email( $from ) ) {
			return $this->check( 'sender', 'fail', __( 'Sender address is invalid', 'submission-inbox' ), __( 'Neither From Email nor the WordPress administrator email can be used as a valid sender.', 'submission-inbox' ), 'settings_sending' );
		}

		$from_domain = strtolower( (string) substr( strrchr( $from, '@' ) ?: '', 1 ) );
		$site_domain = strtolower( (string) wp_parse_url( home_url( '/' ), PHP_URL_HOST ) );
		$site_domain = preg_replace( '/^www\./', '', $site_domain );
		if ( '' !== $site_domain && ! $this->domains_align( $from_domain, $site_domain ) ) {
			return $this->check( 'sender', 'warning', __( 'Sender domain differs from the site', 'submission-inbox' ), __( 'This can be intentional, but the sending provider must authorize the From domain to reduce spam or rejection risk.', 'submission-inbox' ), 'settings_sending' );
		}

		return $this->check( 'sender', 'pass', __( 'Sender address is valid', 'submission-inbox' ), __( 'The sender address is valid and its domain aligns with the site domain. DNS authentication is not tested here.', 'submission-inbox' ), 'none' );
	}

	/** WP-Cron worker check for queued and delayed notifications. */
	private function cron_check() {
		$scheduled = wp_next_scheduled( \SUBIN\Forms\FormSubmissionHandler::NOTIFICATION_WORKER_HOOK );
		$disabled  = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
		if ( ! $scheduled ) {
			return $this->check( 'cron', 'fail', __( 'Notification worker is not scheduled', 'submission-inbox' ), __( 'Queued and delayed notifications may wait until the WordPress cron worker is scheduled again.', 'submission-inbox' ), 'settings_sending' );
		}
		if ( $disabled ) {
			return $this->check( 'cron', 'warning', __( 'Built-in WP-Cron is disabled', 'submission-inbox' ), __( 'The notification worker is scheduled, but WordPress needs an external cron runner to execute it.', 'submission-inbox' ), 'none' );
		}

		return $this->check( 'cron', 'pass', __( 'Notification worker is scheduled', 'submission-inbox' ), __( 'WordPress has a recurring worker for queued and delayed notification delivery.', 'submission-inbox' ), 'none' );
	}

	/** Mail logging freshness check. */
	private function logging_check() {
		$latest = $this->health->latest_email_event( array( 'date_range' => 'all' ) );
		if ( ! $latest || empty( $latest->created_at ) ) {
			return $this->check( 'logging', 'info', __( 'Email log is waiting for activity', 'submission-inbox' ), __( 'No mail events have been recorded yet. This is not a healthy or unhealthy result.', 'submission-inbox' ), 'verify' );
		}

		$timestamp = strtotime( (string) $latest->created_at );
		if ( $timestamp && $timestamp < time() - ( 7 * DAY_IN_SECONDS ) ) {
			return $this->check( 'logging', 'info', __( 'Email activity is older than seven days', 'submission-inbox' ), __( 'Logging has data, but there is no recent event to confirm the current sending path.', 'submission-inbox' ), 'verify' );
		}

		return $this->check( 'logging', 'pass', __( 'Email logging is active', 'submission-inbox' ), __( 'InboxMend has recorded email activity during the last seven days.', 'submission-inbox' ), 'email_log' );
	}

	/** Build one normalized check. */
	private function check( $key, $status, $title, $message, $action ) {
		return array(
			'key'     => substr( sanitize_key( $key ), 0, 50 ),
			'status'  => in_array( $status, array( 'pass', 'warning', 'fail', 'info' ), true ) ? $status : 'info',
			'title'   => sanitize_text_field( $title ),
			'message' => sanitize_text_field( $message ),
			'action'  => in_array( $action, array( 'settings_sending', 'verify', 'email_log', 'none' ), true ) ? $action : 'none',
		);
	}

	/** Compare a mailbox domain with a site domain, allowing subdomains. */
	private function domains_align( $mail_domain, $site_domain ) {
		$mail_domain = trim( strtolower( (string) $mail_domain ), '.' );
		$site_domain = trim( strtolower( (string) $site_domain ), '.' );
		if ( '' === $mail_domain || '' === $site_domain ) {
			return false;
		}

		return $mail_domain === $site_domain
			|| substr( $mail_domain, -strlen( '.' . $site_domain ) ) === '.' . $site_domain
			|| substr( $site_domain, -strlen( '.' . $mail_domain ) ) === '.' . $mail_domain;
	}
}
