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

namespace Hafenstudios\Kurato\Mail;

use Hafenstudios\Core\Mail\Message;

defined( 'ABSPATH' ) || exit;

/**
 * Gemeinsame Basis fuer HTTP-API-Versandtreiber (Brevo, Postmark, Mailgun,
 * SMTP2GO). Kapselt den `wp_remote_post`-Aufruf und die einheitliche Fehler-
 * klassifikation: 429 und 5xx sind voruebergehend (Retry), uebrige 4xx sind
 * permanent (ungueltige Adresse, Auth-Fehler). Jeder Treiber liefert nur noch
 * Endpunkt, Request-Aufbau und die Extraktion der Provider-Message-ID.
 */
abstract class AbstractApiEspDriver implements EspDriver {

	/**
	 * Treiber-Schluessel (z.B. "brevo").
	 *
	 * @return string
	 */
	abstract public function key(): string;

	/**
	 * Ziel-URL des API-Endpunkts.
	 *
	 * @return string
	 */
	abstract protected function endpoint(): string;

	/**
	 * Sind die Zugangsdaten vorhanden?
	 *
	 * @return bool
	 */
	abstract protected function is_configured(): bool;

	/**
	 * Meldung, wenn die Konfiguration fehlt.
	 *
	 * @return string
	 */
	abstract protected function config_error(): string;

	/**
	 * Baut die Request-Bestandteile.
	 *
	 * @param Message $message Nachricht.
	 * @return array{headers:array<string,string>,body:string,method?:string}
	 */
	abstract protected function build_request( Message $message ): array;

	/**
	 * Extrahiert die Provider-Message-ID aus der Erfolgsantwort.
	 *
	 * @param string $body Response-Body.
	 * @return string
	 */
	abstract protected function parse_message_id( string $body ): string;

	/**
	 * @param Message $message Nachricht.
	 * @return bool
	 */
	public function send( Message $message ): bool {
		return $this->send_detailed( $message )->ok;
	}

	/**
	 * @param Message $message Nachricht.
	 * @return SendResult
	 */
	public function send_detailed( Message $message ): SendResult {
		if ( ! $this->is_configured() ) {
			return SendResult::permanent( $this->config_error() );
		}
		if ( '' === $message->to || '' === $message->from_email ) {
			return SendResult::permanent( __( 'Absender oder Empfaenger fehlt.', 'kurato' ) );
		}

		$request  = $this->build_request( $message );
		$response = wp_remote_post(
			$this->endpoint(),
			array(
				'timeout' => 15,
				'method'  => (string) ( $request['method'] ?? 'POST' ),
				'headers' => $request['headers'],
				'body'    => $request['body'],
			)
		);

		if ( is_wp_error( $response ) ) {
			return SendResult::transient( $response->get_error_message() );
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$body = (string) wp_remote_retrieve_body( $response );

		if ( $code >= 200 && $code < 300 ) {
			return SendResult::success( $this->parse_message_id( $body ) );
		}

		$error = 'HTTP ' . $code . ': ' . substr( $body, 0, 200 );
		if ( 429 === $code || $code >= 500 ) {
			return SendResult::transient( $error );
		}
		return SendResult::permanent( $error );
	}

	/**
	 * Kleiner JSON-Helfer: liest einen String-Wert aus einer Response.
	 *
	 * @param string $body Response-Body.
	 * @param string $key  Schluessel.
	 * @return string
	 */
	protected function json_value( string $body, string $key ): string {
		$data = json_decode( $body, true );
		return is_array( $data ) && isset( $data[ $key ] ) ? (string) $data[ $key ] : '';
	}
}
