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

namespace Hafenstudios\Leadlotse\Support;

defined( 'ABSPATH' ) || exit;

/**
 * Reine, testbare Logik rund um die Absender-Adresse (L-F1). Beurteilt, ob eine
 * eingetragene Absender-Domain zur Site-Domain passt und ob es sich um einen
 * Freemail-Anbieter handelt. Freemail- und Fremd-Domain-Absender scheitern beim
 * Empfaenger am SPF-Check und landen im Spam; die Einstellungsseite warnt darauf
 * gestuetzt (Muster der Hans-Karten).
 *
 * Keine WordPress-Abhaengigkeiten: die Site-Domain wird als Zeichenkette
 * hereingereicht, damit die Bewertung ohne WP getestet werden kann.
 */
final class MailSenderCheck {

	/**
	 * Ergebnis: kein Absender eingetragen (es greift der wirksame Default).
	 */
	public const RESULT_EMPTY = 'empty';

	/**
	 * Ergebnis: Absender-Domain passt zur Site-Domain.
	 */
	public const RESULT_OK = 'ok';

	/**
	 * Ergebnis: Absender-Domain ist ein Freemail-Anbieter.
	 */
	public const RESULT_FREEMAIL = 'freemail';

	/**
	 * Ergebnis: Absender-Domain ist eine Fremd-Domain (weder Site noch Freemail).
	 */
	public const RESULT_MISMATCH = 'mismatch';

	/**
	 * Bekannte Freemail-Domains. Bewusst als Absender ungeeignet, weil deren SPF
	 * Fremd-Server nicht autorisiert.
	 *
	 * @var array<int, string>
	 */
	private const FREEMAIL_DOMAINS = array(
		'gmail.com',
		'googlemail.com',
		'outlook.com',
		'outlook.de',
		'hotmail.com',
		'hotmail.de',
		'live.com',
		'live.de',
		'msn.com',
		'yahoo.com',
		'yahoo.de',
		'ymail.com',
		'gmx.de',
		'gmx.net',
		'gmx.at',
		'gmx.ch',
		'gmx.com',
		'web.de',
		't-online.de',
		'freenet.de',
		'aol.com',
		'aol.de',
		'icloud.com',
		'me.com',
		'mac.com',
		'mail.com',
		'proton.me',
		'protonmail.com',
	);

	/**
	 * Extrahiert die (kleingeschriebene) Domain aus einer E-Mail-Adresse; ein
	 * fuehrendes www. wird entfernt.
	 *
	 * @param string $email E-Mail-Adresse.
	 * @return string Domain oder Leerstring.
	 */
	public static function domain_from_email( string $email ): string {
		$email = strtolower( trim( $email ) );
		$at    = strrpos( $email, '@' );
		if ( false === $at ) {
			return '';
		}
		return self::normalize_host( substr( $email, $at + 1 ) );
	}

	/**
	 * Normalisiert einen Hostnamen: klein, ohne Leerraum, ohne fuehrendes www.
	 *
	 * @param string $host Hostname.
	 * @return string
	 */
	public static function normalize_host( string $host ): string {
		$host = strtolower( trim( $host ) );
		if ( 0 === strncmp( $host, 'www.', 4 ) ) {
			$host = substr( $host, 4 );
		}
		return $host;
	}

	/**
	 * Ist die Domain ein bekannter Freemail-Anbieter?
	 *
	 * @param string $domain Domain.
	 * @return bool
	 */
	public static function is_freemail( string $domain ): bool {
		return in_array( self::normalize_host( $domain ), self::FREEMAIL_DOMAINS, true );
	}

	/**
	 * Passt die Absender-Domain zur Site-Domain? Gleichheit sowie ein
	 * Unterdomain-Verhaeltnis (z.B. mail.example.com zu example.com) gelten als Treffer.
	 *
	 * @param string $sender_domain Absender-Domain.
	 * @param string $site_host     Site-Host (aus home_url).
	 * @return bool
	 */
	public static function domain_matches_site( string $sender_domain, string $site_host ): bool {
		$sender = self::normalize_host( $sender_domain );
		$site   = self::normalize_host( $site_host );
		if ( '' === $sender || '' === $site ) {
			return false;
		}
		if ( $sender === $site ) {
			return true;
		}
		// Unterdomain in beide Richtungen (Absender unter Site oder umgekehrt).
		return self::ends_with( $sender, '.' . $site ) || self::ends_with( $site, '.' . $sender );
	}

	/**
	 * Bewertet eine Absender-Adresse gegen die Site-Domain.
	 *
	 * @param string $from_email Eingetragene Absender-Adresse.
	 * @param string $site_host  Site-Host (aus home_url).
	 * @return string Eine der RESULT_*-Konstanten.
	 */
	public static function evaluate( string $from_email, string $site_host ): string {
		$domain = self::domain_from_email( $from_email );
		if ( '' === $domain ) {
			return self::RESULT_EMPTY;
		}
		if ( self::is_freemail( $domain ) ) {
			return self::RESULT_FREEMAIL;
		}
		if ( self::domain_matches_site( $domain, $site_host ) ) {
			return self::RESULT_OK;
		}
		return self::RESULT_MISMATCH;
	}

	/**
	 * Der wirksame Standard-Absender, wenn kein Absender gesetzt ist. Entspricht
	 * dem Fallback des Core-Mailers: wordpress@{Site-Domain}.
	 *
	 * @param string $site_host Site-Host (aus home_url).
	 * @return string
	 */
	public static function default_from_email( string $site_host ): string {
		$host = self::normalize_host( $site_host );
		return '' === $host ? '' : 'wordpress@' . $host;
	}

	/**
	 * Endet $haystack auf $needle? (Ersatz fuer str_ends_with unter PHP 7.4.)
	 *
	 * @param string $haystack Zeichenkette.
	 * @param string $needle   Endung.
	 * @return bool
	 */
	private static function ends_with( string $haystack, string $needle ): bool {
		$len = strlen( $needle );
		if ( 0 === $len ) {
			return true;
		}
		return $len <= strlen( $haystack ) && 0 === substr_compare( $haystack, $needle, -$len );
	}
}
