<?php
/*
Plugin Name: CryoWeave M365 Graph Mailer
Description: Routes all wp_mail() through Microsoft Graph as noreply@cryoweave.com (app-only client credentials) so site/contact-form mail is DMARC-aligned. Falls back to default wp_mail on any failure. Deployed by ClaudeTools 2026-06-23.
Version: 1.0
*/
if ( ! defined( 'ABSPATH' ) ) { exit; }

define( 'CW_MAILER_TENANT',   '44705a37-b5d8-4bb1-882d-e18775612ada' );
define( 'CW_MAILER_CLIENT',   '4003c79e-d4ac-4265-ba36-da783d89ee4d' );
define( 'CW_MAILER_SECRET',   '__SECRET__' );
define( 'CW_MAILER_FROM',     'noreply@cryoweave.com' );
define( 'CW_MAILER_FROMNAME', 'CryoWeave' );

function cw_graph_token() {
	$tok = get_transient( 'cw_graph_token' );
	if ( $tok ) { return $tok; }
	$resp = wp_remote_post(
		'https://login.microsoftonline.com/' . CW_MAILER_TENANT . '/oauth2/v2.0/token',
		array(
			'timeout' => 20,
			'body'    => array(
				'client_id'     => CW_MAILER_CLIENT,
				'client_secret' => CW_MAILER_SECRET,
				'scope'         => 'https://graph.microsoft.com/.default',
				'grant_type'    => 'client_credentials',
			),
		)
	);
	if ( is_wp_error( $resp ) ) { return false; }
	$j = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( empty( $j['access_token'] ) ) { return false; }
	set_transient( 'cw_graph_token', $j['access_token'], max( 60, intval( isset( $j['expires_in'] ) ? $j['expires_in'] : 3600 ) - 120 ) );
	return $j['access_token'];
}

add_filter( 'pre_wp_mail', function ( $null, $atts ) {
	$to      = isset( $atts['to'] ) ? $atts['to'] : array();
	$subject = isset( $atts['subject'] ) ? $atts['subject'] : '';
	$message = isset( $atts['message'] ) ? $atts['message'] : '';
	$headers = isset( $atts['headers'] ) ? $atts['headers'] : array();

	$cc = array(); $bcc = array(); $replyto = array(); $ctype = 'Text';
	if ( ! is_array( $headers ) ) {
		$headers = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
	}
	foreach ( (array) $headers as $h ) {
		if ( strpos( $h, ':' ) === false ) { continue; }
		list( $k, $v ) = array_map( 'trim', explode( ':', $h, 2 ) );
		$kl = strtolower( $k );
		if ( 'cc' === $kl ) { $cc = array_merge( $cc, array_map( 'trim', explode( ',', $v ) ) ); }
		elseif ( 'bcc' === $kl ) { $bcc = array_merge( $bcc, array_map( 'trim', explode( ',', $v ) ) ); }
		elseif ( 'reply-to' === $kl ) { $replyto[] = $v; }
		elseif ( 'content-type' === $kl && stripos( $v, 'html' ) !== false ) { $ctype = 'HTML'; }
	}
	if ( ! is_array( $to ) ) { $to = array_map( 'trim', explode( ',', $to ) ); }

	$addr = function ( $a ) {
		if ( preg_match( '/<([^>]+)>/', $a, $m ) ) { return trim( $m[1] ); }
		return trim( $a );
	};
	$rcpt = function ( $list ) use ( $addr ) {
		$o = array();
		foreach ( (array) $list as $a ) {
			$e = $addr( $a );
			if ( $e ) { $o[] = array( 'emailAddress' => array( 'address' => $e ) ); }
		}
		return $o;
	};

	$token = cw_graph_token();
	if ( ! $token ) { return $null; } // fall back to default wp_mail

	$payload = array(
		'message' => array(
			'subject'      => $subject,
			'body'         => array( 'contentType' => $ctype, 'content' => $message ),
			'from'         => array( 'emailAddress' => array( 'address' => CW_MAILER_FROM, 'name' => CW_MAILER_FROMNAME ) ),
			'toRecipients' => $rcpt( $to ),
		),
		'saveToSentItems' => false,
	);
	if ( $cc )      { $payload['message']['ccRecipients']  = $rcpt( $cc ); }
	if ( $bcc )     { $payload['message']['bccRecipients'] = $rcpt( $bcc ); }
	if ( $replyto ) { $payload['message']['replyTo']       = $rcpt( $replyto ); }

	$resp = wp_remote_post(
		'https://graph.microsoft.com/v1.0/users/' . rawurlencode( CW_MAILER_FROM ) . '/sendMail',
		array(
			'timeout' => 25,
			'headers' => array( 'Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json' ),
			'body'    => wp_json_encode( $payload ),
		)
	);
	if ( is_wp_error( $resp ) ) { return $null; } // fall back
	$code = wp_remote_retrieve_response_code( $resp );
	if ( 202 === intval( $code ) ) { return true; } // handled
	return $null; // anything else: fall back to default wp_mail
}, 10, 2 );
