<?php
/**
 * @package Hafenstudios\Kurato
 */

namespace Hafenstudios\Kurato\Mail;

use Hafenstudios\Core\Events\EventBus;
use Hafenstudios\Core\Mail\Message;

defined( 'ABSPATH' ) || exit;

/**
 * Zustell-Protokoll (K-M1): lauscht auf das Core-Event `mail_sent` und haelt eine
 * kleine Sichtbarkeit ueber den Versand bereit - den letzten erfolgreichen
 * Versand und einen Ringpuffer der letzten Fehlversande.
 *
 * Bewusst datensparsam: gespeichert werden NUR Zustell-Metadaten - Zeitpunkt
 * (UTC), maskierter Empfaenger (a***@domain), gekuerzter Betreff und der Treiber.
 * KEINE IP-Adressen und KEINE Mail-Inhalte. Ablage in zwei Optionen (Ringpuffer),
 * daher kein Schema-Zuwachs.
 *
 * Das Core-Event feuert bei jedem Versand ueber den Core-Mailer (Message, ok).
 * Der Direkt-Versand der ESP-Treiber laeuft nicht ueber den Core-Mailer; dessen
 * Fehler sind ueber die Queue-Fehler ({@see QueueRepository::recent_failures()})
 * sichtbar, die die Einstellungsseite zusaetzlich anzeigt.
 */
final class DeliveryLog {

	/**
	 * Option mit dem Ringpuffer der letzten Fehlversande.
	 */
	public const OPTION_FAILURES = 'kurato_delivery_failures';

	/**
	 * Option mit dem letzten erfolgreichen Versand.
	 */
	public const OPTION_LAST_OK = 'kurato_delivery_last_ok';

	/**
	 * Maximale Anzahl gehaltener Fehlversande.
	 */
	public const MAX_FAILURES = 20;

	/**
	 * Verdrahtet den Listener auf das Core-Event `mail_sent`.
	 *
	 * @return void
	 */
	public function register(): void {
		EventBus::on( 'mail_sent', array( $this, 'on_mail_sent' ), 10, 2 );
	}

	/**
	 * Nimmt ein Versandergebnis auf.
	 *
	 * @param Message $message Versandte Nachricht.
	 * @param bool    $ok      Erfolg laut Treiber.
	 * @return void
	 */
	public function on_mail_sent( $message, $ok ): void {
		if ( ! $message instanceof Message ) {
			return;
		}

		if ( $ok ) {
			update_option(
				self::OPTION_LAST_OK,
				array(
					'time' => gmdate( 'Y-m-d H:i:s' ),
					'to'   => self::mask_email( $message->to ),
				)
			);
			return;
		}

		$entry = array(
			'time'    => gmdate( 'Y-m-d H:i:s' ),
			'to'      => self::mask_email( $message->to ),
			'subject' => self::shorten( $message->subject ),
			'driver'  => $this->driver_key(),
		);

		$failures = get_option( self::OPTION_FAILURES, array() );
		$failures = is_array( $failures ) ? $failures : array();
		// Neuester zuerst, Kappung auf MAX_FAILURES.
		array_unshift( $failures, $entry );
		$failures = array_slice( $failures, 0, self::MAX_FAILURES );
		update_option( self::OPTION_FAILURES, $failures );
	}

	/**
	 * Die letzten Fehlversande (neuester zuerst).
	 *
	 * @return array<int, array<string, mixed>>
	 */
	public static function failures(): array {
		$failures = get_option( self::OPTION_FAILURES, array() );
		return is_array( $failures ) ? $failures : array();
	}

	/**
	 * Der letzte erfolgreiche Versand oder null.
	 *
	 * @return array<string, mixed>|null
	 */
	public static function last_ok(): ?array {
		$last = get_option( self::OPTION_LAST_OK, null );
		return is_array( $last ) ? $last : null;
	}

	/**
	 * Maskiert eine E-Mail-Adresse zu "a***@domain". Ohne @ oder ohne Local-Part
	 * bleibt nur "***" (nie die volle Adresse speichern).
	 *
	 * @param string $email Adresse.
	 * @return string
	 */
	public static function mask_email( string $email ): string {
		$email = trim( $email );
		$at    = strpos( $email, '@' );
		if ( false === $at || 0 === $at ) {
			return '***';
		}
		$first  = substr( $email, 0, 1 );
		$domain = substr( $email, $at + 1 );
		return $first . '***@' . $domain;
	}

	/**
	 * Kuerzt einen Betreff fuer die Anzeige.
	 *
	 * @param string $subject Betreff.
	 * @return string
	 */
	private static function shorten( string $subject ): string {
		$subject = trim( $subject );
		if ( strlen( $subject ) <= 60 ) {
			return $subject;
		}
		return substr( $subject, 0, 57 ) . '...';
	}

	/**
	 * Bester verfuegbarer Treiber-Schluessel fuer das Protokoll. Das `mail_sent`-
	 * Event traegt den Treiber nicht; der Core-Mailer nutzt die Option
	 * `hs_core_mail`. Fehlt sie, bleibt der Wert leer.
	 *
	 * @return string
	 */
	private function driver_key(): string {
		$config = get_option( 'hs_core_mail', array() );
		$config = is_array( $config ) ? $config : array();
		return (string) ( $config['driver'] ?? '' );
	}
}
