<?php
/**
 * Status tab helpers for the Mail Doctor admin UI.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Admin\Modules;

use MailDoctor\Checks;
use MailDoctor\Helpers\Settings;
use MailDoctor\Logger;
use MailDoctor\Profiles;
use MailDoctor\Retry;

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

/**
 * Provides rendering and AJAX utilities for the status dashboard.
 */
trait Status_Trait {


	/**
	 * Render status dashboard.
	 *
	 * @return void
	 */
	protected static function render_status_tab(): void {
		$active_tab       = 'status';
		$base_url         = self::page_url();
		$test_email       = get_option( 'admin_email' );
		$provider_options = self::get_status_provider_options();

		include MAIL_DOCTOR_PATH . 'templates/admin/status.php';
	}

	/**
	 * Provider choices for status quick actions.
	 *
	 * @return array<string,string>
	 */
	protected static function get_status_provider_options(): array {
		if ( class_exists( Profiles::class ) ) {
			$choices = Profiles::choices();
		} else {
			$choices = array();
		}

		if ( empty( $choices ) ) {
			$choices = array(
				'default' => esc_html__( 'Default SMTP Settings', 'mail-doctor' ),
			);
		}

		/**
		 * Filter provider dropdown options for status quick actions.
		 *
		 * @since 1.3.0
		 *
		 * @param array<string,string> $choices Provider choices map.
		 */
		return apply_filters( 'mail_doctor_status_provider_options', $choices );
	}

	/**
	 * AJAX handler: fetch status cards from live data.
	 *
	 * @return void
	 */
	public static function ajax_get_status_cards(): void {
check_ajax_referer( 'mail_doctor_status_cards_nonce' );
		self::assert_capability();

		$domain        = self::determine_sending_domain();
		$dns           = Checks::dns_summary( $domain );
		$queue         = Checks::queue_stats();
		$next          = wp_next_scheduled( Retry::CRON_HOOK );
		$metrics       = Logger::get_metrics( 1 );
		$series        = Logger::get_metrics_series( 24, 'hour' );
		$failures      = Logger::get_failure_breakdown( 24, 4 );
		$providers     = Logger::get_provider_performance( 24, 4 );
		$queue_health  = Logger::summarize_retry_queue( 50 );
		$metrics_trend = self::summarize_metrics_trend( $series['series'] ?? array() );

		$dns_labels = array(
			'spf'     => __( 'SPF', 'mail-doctor' ),
			'dkim'    => __( 'DKIM', 'mail-doctor' ),
			'dmarc'   => __( 'DMARC', 'mail-doctor' ),
			'bimi'    => __( 'BIMI', 'mail-doctor' ),
			'mta_sts' => __( 'MTA-STS', 'mail-doctor' ),
			'tls_rpt' => __( 'TLS-RPT', 'mail-doctor' ),
		);

		$dns_items = array();
		foreach ( $dns_labels as $record_key => $label ) {
			$raw           = $dns[ $record_key ] ?? array();
			$status_raw    = isset( $raw['status'] ) ? (string) $raw['status'] : '';
			$status_mapped = self::map_dns_state( $status_raw );
			$dns_items[]   = array(
				'key'     => $record_key,
				'label'   => $label,
				'status'  => $status_mapped,
				'message' => isset( $raw['message'] ) ? (string) $raw['message'] : '',
				'value'   => isset( $raw['value'] ) ? (string) $raw['value'] : '',
			);
		}

		$queue_raw = array(
			'queued'      => (int) ( $queue['queued'] ?? 0 ),
			'failed'      => (int) ( $queue['failed'] ?? 0 ),
			'quarantined' => (int) ( $queue['quarantined'] ?? 0 ),
		);

		$sent   = (int) ( $metrics['sent'] ?? 0 );
		$failed = (int) ( $metrics['failed'] ?? 0 );
		$total  = (int) ( $metrics['total'] ?? ( $sent + $failed ) );

		$success_rate = null;
		if ( array_key_exists( 'success_rate', $metrics ) && null !== $metrics['success_rate'] ) {
			$success_rate = (float) $metrics['success_rate'];
		} elseif ( $total > 0 ) {
			$success_rate = ( (float) $sent / (float) $total ) * 100;
		}

		$median_latency = null;
		if ( isset( $metrics['median_latency'] ) ) {
			$median_latency = (float) $metrics['median_latency'];
		} elseif ( isset( $metrics['median_duration_ms'] ) ) {
			$median_latency = (float) $metrics['median_duration_ms'];
		}

		$avg_latency = null;
		if ( isset( $metrics['avg_latency'] ) ) {
			$avg_latency = (float) $metrics['avg_latency'];
		} elseif ( isset( $metrics['avg_duration_ms'] ) ) {
			$avg_latency = (float) $metrics['avg_duration_ms'];
		}

		$median_latency = null !== $median_latency ? (int) round( $median_latency ) : 0;
		$avg_latency    = null !== $avg_latency ? (int) round( $avg_latency ) : 0;

		$data = array(
			'dns'           => $dns_items,
			'queue'         => array(
				'queued'      => number_format_i18n( $queue_raw['queued'] ),
				'failed'      => number_format_i18n( $queue_raw['failed'] ),
				'quarantined' => number_format_i18n( $queue_raw['quarantined'] ),
				'next'        => $next ? sprintf(
					/* translators: %s: human readable time. */
					esc_html__( 'in %s', 'mail-doctor' ),
					human_time_diff( time(), $next )
				) : esc_html__( 'Not scheduled', 'mail-doctor' ),
			),
			'stats'         => array(
				'successRate'   => $success_rate,
				'medianLatency' => $median_latency,
				'avgLatency'    => $avg_latency,
				'total'         => $total,
			),
			'queueRaw'      => $queue_raw,
			'statsRaw'      => array(
				'sent'        => $sent,
				'failed'      => $failed,
				'total'       => $total,
				'successRate' => $success_rate,
			),
			'warnings'      => self::compile_status_warnings( $dns, $queue, $next ),
			'metricsSeries' => $series,
			'metricsTrend'  => $metrics_trend,
			'failures'      => $failures,
			'providers'     => self::decorate_provider_performance( $providers ),
			'queueHealth'   => self::format_queue_health( $queue_health ),
		);

		wp_send_json_success( $data );
	}

	/**
	 * Determine domain used for DNS diagnostics.
	 *
	 * @return string
	 */
	protected static function determine_sending_domain(): string {
		$settings   = Settings::all();
		$from_email = isset( $settings['from_email'] ) ? sanitize_email( (string) $settings['from_email'] ) : '';

		if ( $from_email && is_email( $from_email ) ) {
			$parts  = explode( '@', $from_email );
			$domain = strtolower( array_pop( $parts ) );
			if ( $domain ) {
				return $domain;
			}
		}

		$hosts = array(
			wp_parse_url( home_url(), PHP_URL_HOST ),
			wp_parse_url( site_url(), PHP_URL_HOST ),
		);

		foreach ( $hosts as $host ) {
			if ( ! empty( $host ) ) {
				$host = strtolower( (string) $host );
				return preg_replace( '/^www\./', '', $host );
			}
		}

		return '';
	}

	/**
	 * Map DNS status to badge state.
	 *
	 * @param string $status Raw status value.
	 * @return string
	 */
	protected static function map_dns_state( string $status ): string {
		$status = strtolower( trim( $status ) );

		switch ( $status ) {
			case 'present':
			case 'pass':
			case 'valid':
			case 'ok':
				return 'ok';
			case 'missing':
			case 'fail':
			case 'failed':
			case 'invalid':
			case 'error':
			case 'unavailable':
				return 'fail';
			case 'warning':
			default:
				return 'warn';
		}
	}

	/**
	 * Summarise trend direction for recent metrics.
	 *
	 * @param array<int, array<string, mixed>> $series Metrics series.
	 * @return array<string, mixed>
	 */
	protected static function summarize_metrics_trend( array $series ): array {
		$count = count( $series );
		if ( 0 === $count ) {
			return array(
				'current'        => null,
				'previous'       => null,
				'delta'          => null,
				'direction'      => 'flat',
				'currentBucket'  => array(),
				'previousBucket' => array(),
			);
		}

		$current_bucket  = null;
		$previous_bucket = null;

		for ( $i = $count - 1; $i >= 0; $i-- ) {
			$bucket = $series[ $i ];
			if ( null === $current_bucket && isset( $bucket['success_rate'] ) && null !== $bucket['success_rate'] ) {
				$current_bucket = $bucket;
				continue;
			}

			if ( $current_bucket && isset( $bucket['success_rate'] ) && null !== $bucket['success_rate'] ) {
				$previous_bucket = $bucket;
				break;
			}
		}

		$current_rate  = $current_bucket && isset( $current_bucket['success_rate'] ) ? (float) $current_bucket['success_rate'] : null;
		$previous_rate = $previous_bucket && isset( $previous_bucket['success_rate'] ) ? (float) $previous_bucket['success_rate'] : null;

		$delta     = ( null !== $current_rate && null !== $previous_rate ) ? $current_rate - $previous_rate : null;
		$direction = 'flat';
		if ( null !== $delta ) {
			if ( $delta > 0.5 ) {
				$direction = 'up';
			} elseif ( $delta < -0.5 ) {
				$direction = 'down';
			}
		}

		return array(
			'current'        => null !== $current_rate ? round( $current_rate, 1 ) : null,
			'previous'       => null !== $previous_rate ? round( $previous_rate, 1 ) : null,
			'delta'          => null !== $delta ? round( $delta, 1 ) : null,
			'direction'      => $direction,
			'currentBucket'  => $current_bucket ?: array(),
			'previousBucket' => $previous_bucket ?: array(),
		);
	}

	/**
	 * Decorate provider stats with status metadata.
	 *
	 * @param array<int, array<string, mixed>> $providers Provider stats.
	 * @return array<int, array<string, mixed>>
	 */
	protected static function decorate_provider_performance( array $providers ): array {
		$decorated = array();

		foreach ( $providers as $provider ) {
			$rate   = isset( $provider['success_rate'] ) ? (float) $provider['success_rate'] : 0.0;
			$total  = (int) ( ( $provider['sent'] ?? 0 ) + ( $provider['failed'] ?? 0 ) );
			$status = 'ok';
			if ( $rate >= 98.0 ) {
				$status = 'ok';
			} elseif ( $rate >= 92.0 ) {
				$status = 'warn';
			} else {
				$status = 'fail';
			}

			$status_label = array(
				'ok'   => __( 'Healthy', 'mail-doctor' ),
				'warn' => __( 'Watch', 'mail-doctor' ),
				'fail' => __( 'Critical', 'mail-doctor' ),
			);

			$decorated[] = array_merge(
				$provider,
				array(
					'status'             => $status,
					'status_label'       => $status_label[ $status ] ?? __( 'Status', 'mail-doctor' ),
					'success_rate_label' => sprintf( '%s%%', number_format_i18n( round( $rate, 1 ), 1 ) ),
					'volume_label'       => sprintf(
						/* translators: %s: number of sends */
						_n( '%s send', '%s sends', $total, 'mail-doctor' ),
						number_format_i18n( $total )
					),
					/* translators: %d: latency in ms */
					'latency_label'      => ! empty( $provider['latency'] ) ? sprintf( __( '%d ms', 'mail-doctor' ), (int) $provider['latency'] ) : __( 'n/a', 'mail-doctor' ),
				)
			);
		}

		return $decorated;
	}

	/**
	 * Format queue health summary with human-readable labels.
	 *
	 * @param array<string, mixed> $health Queue health metrics.
	 * @return array<string, mixed>
	 */
	protected static function format_queue_health( array $health ): array {
		$now = time();

		$avg_attempts      = isset( $health['avg_attempts'] ) ? (float) $health['avg_attempts'] : 0.0;
		$oldest_queued     = isset( $health['oldest_queued_seconds'] ) ? (int) $health['oldest_queued_seconds'] : 0;
		$oldest_quarantine = isset( $health['oldest_quarantine_seconds'] ) ? (int) $health['oldest_quarantine_seconds'] : 0;
		$next_retry        = isset( $health['next_retry_seconds'] ) ? (int) $health['next_retry_seconds'] : 0;
		$queued_count      = isset( $health['queued_count'] ) ? (int) $health['queued_count'] : 0;
		$quarantine_count  = isset( $health['quarantine_count'] ) ? (int) $health['quarantine_count'] : 0;

		$queued_label = $oldest_queued > 0
			/* translators: %s: relative time */
			? sprintf( __( '%s ago', 'mail-doctor' ), human_time_diff( $now - $oldest_queued, $now ) )
			: __( 'No queued messages', 'mail-doctor' );

		$quarantine_label = $oldest_quarantine > 0
			/* translators: %s: relative time */
			? sprintf( __( '%s ago', 'mail-doctor' ), human_time_diff( $now - $oldest_quarantine, $now ) )
			: __( 'No quarantined messages', 'mail-doctor' );

		$next_retry_label = $next_retry > 0
			/* translators: %s: relative time */
			? sprintf( __( 'in %s', 'mail-doctor' ), human_time_diff( $now, $now + $next_retry ) )
			: __( 'Not scheduled', 'mail-doctor' );

		return array(
			'avgAttempts'             => round( $avg_attempts, 1 ),
			'avgAttemptsLabel'        => number_format_i18n( round( $avg_attempts, 1 ), 1 ),
			'queuedCount'             => $queued_count,
			'queuedCountLabel'        => number_format_i18n( $queued_count ),
			'quarantineCount'         => $quarantine_count,
			'quarantineCountLabel'    => number_format_i18n( $quarantine_count ),
			'oldestQueuedSeconds'     => $oldest_queued,
			'oldestQueuedLabel'       => $queued_label,
			'oldestQuarantineSeconds' => $oldest_quarantine,
			'oldestQuarantineLabel'   => $quarantine_label,
			'nextRetrySeconds'        => $next_retry,
			'nextRetryLabel'          => $next_retry_label,
		);
	}

	/**
	 * Generate warning messages for status dashboard.
	 *
	 * @param array<string, mixed> $dns  DNS summary.
	 * @param array<string, mixed> $queue Queue stats.
	 * @param int|false            $next Next scheduled retry timestamp.
	 * @return array<int, string>
	 */
	protected static function compile_status_warnings( array $dns, array $queue, $next ): array {
		$warnings = array();

		foreach ( array( 'spf', 'dkim', 'dmarc' ) as $record ) {
			$status = strtolower( $dns[ $record ]['status'] ?? '' );
			if ( in_array( $status, array( 'missing', 'warning', 'unavailable', 'fail', 'failed' ), true ) ) {
				$message = $dns[ $record ]['message'] ?? '';
				if ( '' === $message ) {
					$label      = strtoupper( $record );
					$warnings[] = sprintf(
						/* translators: %s: DNS record name. */
						__( '%s record requires attention.', 'mail-doctor' ),
						$label
					);
				} else {
					$warnings[] = $message;
				}
			}
		}

		$failed      = isset( $queue['failed'] ) ? (int) $queue['failed'] : 0;
		$quarantined = isset( $queue['quarantined'] ) ? (int) $queue['quarantined'] : 0;

		if ( $failed > 0 ) {
			$warnings[] = sprintf(
				/* translators: %d: number of failed emails. */
				__( '%d email(s) failed in the recent logs. Review the SMTP configuration.', 'mail-doctor' ),
				$failed
			);
		}

		if ( $quarantined > 0 ) {
			$warnings[] = sprintf(
				/* translators: %d: number of quarantined emails. */
				__( '%d email(s) are quarantined awaiting manual review.', 'mail-doctor' ),
				$quarantined
			);
		}

		if ( ! $next ) {
			$warnings[] = __( 'Retry worker is not scheduled. Confirm WordPress cron is functioning.', 'mail-doctor' );
		}

		/**
		 * Filter warnings displayed in the status dashboard.
		 *
		 * @since 1.3.0
		 *
		 * @param array<int, string> $warnings Warning messages.
		 * @param array<string,mixed> $dns     DNS summary.
		 * @param array<string,mixed> $queue   Queue statistics.
		 * @param int|false           $next    Next retry timestamp.
		 */
		return apply_filters( 'mail_doctor_status_warnings', $warnings, $dns, $queue, $next );
	}

	/**
	 * AJAX handler: immediately run the retry queue.
	 *
	 * @return void
	 */
	public static function ajax_run_queue_now(): void {
check_ajax_referer( 'mail_doctor_run_queue_nonce' );
		self::assert_capability();

		$processed = Retry::run();

		wp_send_json_success(
			array(
				'message' => $processed
					? sprintf(
						/* translators: %d: number of emails processed. */
						esc_html__( 'Queue worker processed %d pending email(s).', 'mail-doctor' ),
						(int) $processed
					)
					: esc_html__( 'No pending emails were ready for processing.', 'mail-doctor' ),
			)
		);
	}
}
