<?php
/**
 * Generic HTTP transport.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Transports;

use WP_Error;

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

/**
 * Dispatch messages to custom HTTP endpoints.
 */
class Generic_Http {
	/**
	 * Send HTTP request with message payload.
	 *
	 * @param array<string,mixed> $args      Normalized mail args.
	 * @param array<string,mixed> $settings  Plugin settings.
	 * @return array<string,mixed>|WP_Error
	 */
	public static function send( array $args, array $settings ) {
		$endpoint = trim( (string) ( $settings['generic_api_endpoint'] ?? '' ) );
		$method   = strtoupper( (string) ( $settings['generic_api_method'] ?? 'POST' ) );
		$token    = trim( (string) ( $settings['generic_api_auth_token'] ?? '' ) );

		if ( '' === $endpoint ) {
			return new WP_Error( 'mail_doctor_generic_missing_endpoint', __( 'Generic HTTP endpoint is not configured.', 'mail-doctor' ) );
		}

		if ( ! in_array( $method, array( 'POST', 'PUT' ), true ) ) {
			$method = 'POST';
		}

		$recipients = Utils::recipients_from_args( $args );
		if ( empty( $recipients['to'] ) && empty( $recipients['cc'] ) && empty( $recipients['bcc'] ) ) {
			return new WP_Error( 'mail_doctor_generic_missing_recipients', __( 'At least one recipient is required to deliver via the generic HTTP endpoint.', 'mail-doctor' ) );
		}

		$sender = Utils::sender_from_settings( $settings );

		$bodies  = Utils::message_bodies( $args );
		$payload = array(
			'from'    => $sender,
			'to'      => $recipients['to'],
			'cc'      => $recipients['cc'],
			'bcc'     => $recipients['bcc'],
			'subject' => (string) ( $args['subject'] ?? '' ),
			'text'    => (string) $bodies['text'],
		);

		if ( null !== $bodies['html'] ) {
			$payload['html'] = (string) $bodies['html'];
		}

		$headers_map = Utils::headers_to_map( $args['headers'] ?? array() );
		if ( ! empty( $headers_map ) ) {
			$payload['headers'] = $headers_map;
		}

		$attachments = Utils::attachment_payloads( $args['attachments'] ?? array() );
		if ( ! empty( $attachments ) ) {
			$payload['attachments'] = $attachments;
		}

		$request_args = array(
			'method'  => $method,
			'timeout' => 30,
			'headers' => array( 'Content-Type' => 'application/json' ),
			'body'    => wp_json_encode( $payload ),
		);

		if ( '' !== $token ) {
			$request_args['headers']['Authorization'] = 'Bearer ' . $token;
		}

		$response = wp_remote_request( $endpoint, $request_args );

		if ( is_wp_error( $response ) ) {
			return new WP_Error( 'mail_doctor_generic_request_error', $response->get_error_message(), array( 'transport' => 'generic_http' ) );
		}

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

		if ( $code < 200 || $code >= 300 ) {
			return new WP_Error(
				'mail_doctor_generic_failed',
				__( 'Generic endpoint returned an error.', 'mail-doctor' ),
				array(
					'status'   => $code,
					'response' => $body,
				)
			);
		}

		return array(
			'provider_code' => (string) $code,
			'status'        => (int) $code,
			'raw'           => $body,
		);
	}

	/**
	 * Check connectivity to endpoint.
	 *
	 * @param array<string,mixed> $settings Plugin settings.
	 * @return array<string,mixed>
	 */
	public static function check_connection( array $settings ): array {
		$endpoint = trim( (string) ( $settings['generic_api_endpoint'] ?? '' ) );
		$method   = strtoupper( (string) ( $settings['generic_api_method'] ?? 'POST' ) );
		$token    = trim( (string) ( $settings['generic_api_auth_token'] ?? '' ) );

		if ( '' === $endpoint ) {
			return array(
				'success' => false,
				'message' => __( 'Generic HTTP endpoint is missing.', 'mail-doctor' ),
				'data'    => array(
					'host'       => '',
					'encryption' => 'https',
					'auth'       => false,
					'debug'      => array(),
				),
			);
		}

		$host   = wp_parse_url( $endpoint, PHP_URL_HOST );
		$scheme = strtolower( (string) wp_parse_url( $endpoint, PHP_URL_SCHEME ) );
		$secure = 'https' === $scheme;
		$debug  = array();

		$request_args = array(
			'method'  => 'HEAD',
			'timeout' => 10,
			'headers' => array(),
		);

		if ( '' !== $token ) {
			$request_args['headers']['Authorization'] = 'Bearer ' . $token;
		}

		$debug[]  = sprintf( 'HEAD %s', $endpoint );
		$response = wp_remote_request( $endpoint, $request_args );

		if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) >= 400 ) {
			$debug[] = is_wp_error( $response ) ? $response->get_error_message() : wp_remote_retrieve_response_message( $response );
			$debug[] = 'Falling back to GET probe.';

			$request_args['method'] = 'GET';
			$response               = wp_remote_request( $endpoint, $request_args );
		}

		if ( is_wp_error( $response ) ) {
			$debug[] = $response->get_error_message();
			return array(
				'success' => false,
				'message' => $response->get_error_message(),
				'data'    => array(
					'host'       => $host,
					'encryption' => $secure ? 'https' : 'none',
					'auth'       => '' !== $token,
					'debug'      => $debug,
				),
			);
		}

		$code    = wp_remote_retrieve_response_code( $response );
		$debug[] = sprintf( 'Response: %d %s', $code, wp_remote_retrieve_response_message( $response ) );

		if ( $code >= 200 && $code < 400 ) {
			return array(
				'success' => true,
				'message' => __( 'Endpoint reachable. Sending will include live payloads.', 'mail-doctor' ),
				'data'    => array(
					'host'       => $host,
					'encryption' => $secure ? 'https' : 'none',
					'auth'       => '' !== $token,
					'debug'      => $debug,
				),
			);
		}

		return array(
			'success' => false,
			'message' => __( 'Generic endpoint responded with an error status.', 'mail-doctor' ),
			'data'    => array(
				'host'       => $host,
				'encryption' => $secure ? 'https' : 'none',
				'auth'       => '' !== $token,
				'debug'      => $debug,
			),
		);
	}
}
