<?php
/**
 * Invio SMS tramite provider di terze parti (Twilio o Clickatell),
 * a pagamento a consumo presso il provider scelto — a differenza di
 * SPIDy SMS Gateway (versione PRO), che usa una SIM personale/aziendale
 * senza costo per messaggio.
 *
 * @package SPIDy_WP
 */

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

class SPIDy_WP_SMS {

	const OPTION_PROVIDER          = 'spidy_wp_sms_provider'; // 'none' | 'twilio' | 'clickatell'.
	const OPTION_TWILIO_SID        = 'spidy_wp_sms_twilio_sid';
	const OPTION_TWILIO_TOKEN      = 'spidy_wp_sms_twilio_token';
	const OPTION_TWILIO_FROM       = 'spidy_wp_sms_twilio_from';
	const OPTION_CLICKATELL_APIKEY = 'spidy_wp_sms_clickatell_apikey';

	public static function get_provider(): string {
		$provider = (string) get_option( self::OPTION_PROVIDER, 'none' );
		return in_array( $provider, array( 'twilio', 'clickatell' ), true ) ? $provider : 'none';
	}

	public static function is_configured(): bool {
		switch ( self::get_provider() ) {
			case 'twilio':
				return '' !== get_option( self::OPTION_TWILIO_SID, '' )
					&& '' !== get_option( self::OPTION_TWILIO_TOKEN, '' )
					&& '' !== get_option( self::OPTION_TWILIO_FROM, '' );
			case 'clickatell':
				return '' !== get_option( self::OPTION_CLICKATELL_APIKEY, '' );
			default:
				return false;
		}
	}

	/**
	 * Invia un SMS tramite il provider attualmente configurato.
	 *
	 * @param string $to_number Numero destinatario in formato internazionale (es. +393401234567).
	 * @param string $message   Testo del messaggio.
	 * @return true|WP_Error
	 */
	/**
	 * Registra un invio fallito nel log visibile in bacheca (ultimi 20).
	 * Usato sia dal test manuale che da un login reale, per poter
	 * diagnosticare problemi di configurazione senza dover riprodurli.
	 */
	public static function log_error( string $phone_number, string $reason ) {
		$log = get_option( 'spidy_wp_sms_last_errors', array() );
		if ( ! is_array( $log ) ) {
			$log = array();
		}

		array_unshift(
			$log,
			array(
				'time'   => current_time( 'mysql' ),
				'phone'  => $phone_number,
				'reason' => $reason,
			)
		);

		$log = array_slice( $log, 0, 20 );

		update_option( 'spidy_wp_sms_last_errors', $log, false );
	}

	public static function send( string $to_number, string $message ) {
		if ( ! self::is_configured() ) {
			return new WP_Error( 'spidy_wp_sms_not_configured', __( 'Nessun provider SMS configurato.', 'spidy-2fa-login' ) );
		}

		switch ( self::get_provider() ) {
			case 'twilio':
				return self::send_via_twilio( $to_number, $message );
			case 'clickatell':
				return self::send_via_clickatell( $to_number, $message );
			default:
				return new WP_Error( 'spidy_wp_sms_not_configured', __( 'Nessun provider SMS configurato.', 'spidy-2fa-login' ) );
		}
	}

	/**
	 * Documentazione Twilio: https://www.twilio.com/docs/messaging/api/message-resource
	 * POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
	 * Basic Auth: AccountSid:AuthToken — corpo form-urlencoded: To, From, Body.
	 *
	 * @return true|WP_Error
	 */
	private static function send_via_twilio( string $to_number, string $message ) {
		$sid   = (string) get_option( self::OPTION_TWILIO_SID, '' );
		$token = (string) get_option( self::OPTION_TWILIO_TOKEN, '' );
		$from  = (string) get_option( self::OPTION_TWILIO_FROM, '' );

		$url = sprintf( 'https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json', rawurlencode( $sid ) );

		$response = wp_remote_post(
			$url,
			array(
				'timeout' => 15,
				'headers' => array(
					'Authorization' => 'Basic ' . base64_encode( $sid . ':' . $token ),
				),
				'body'    => array(
					'To'   => $to_number,
					'From' => $from,
					'Body' => $message,
				),
			)
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( $code >= 200 && $code < 300 ) {
			return true;
		}

		$detail = is_array( $body ) && isset( $body['message'] ) ? sanitize_text_field( $body['message'] ) : '';

		return new WP_Error(
			'spidy_wp_sms_twilio_failed',
			sprintf(
				/* translators: 1: codice HTTP, 2: messaggio di errore Twilio (se presente) */
				__( 'Invio SMS via Twilio fallito (HTTP %1$d). %2$s', 'spidy-2fa-login' ),
				$code,
				$detail
			)
		);
	}

	/**
	 * Documentazione Clickatell: https://help.clickatell.com/developers-api-reference/sms-api
	 * POST https://platform.clickatell.com/messages
	 * Header "Authorization" = API Key (senza prefisso "Bearer"), corpo JSON: content, to[].
	 *
	 * @return true|WP_Error
	 */
	private static function send_via_clickatell( string $to_number, string $message ) {
		$api_key = (string) get_option( self::OPTION_CLICKATELL_APIKEY, '' );

		$response = wp_remote_post(
			'https://platform.clickatell.com/messages',
			array(
				'timeout' => 15,
				'headers' => array(
					'Authorization' => $api_key,
					'Content-Type'  => 'application/json',
					'Accept'        => 'application/json',
				),
				'body'    => wp_json_encode(
					array(
						'content' => $message,
						'to'      => array( $to_number ),
					)
				),
			)
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		$accepted = false;
		$detail   = '';

		if ( is_array( $body ) ) {
			if ( isset( $body['messages'][0]['accepted'] ) && true === $body['messages'][0]['accepted'] ) {
				$accepted = true;
			}
			if ( isset( $body['messages'][0]['error'] ) && is_string( $body['messages'][0]['error'] ) ) {
				$detail = sanitize_text_field( $body['messages'][0]['error'] );
			} elseif ( isset( $body['error'] ) && is_string( $body['error'] ) ) {
				$detail = sanitize_text_field( $body['error'] );
			}
		}

		if ( $accepted && $code >= 200 && $code < 300 ) {
			return true;
		}

		return new WP_Error(
			'spidy_wp_sms_clickatell_failed',
			sprintf(
				/* translators: 1: codice HTTP, 2: messaggio di errore Clickatell (se presente) */
				__( 'Invio SMS via Clickatell fallito (HTTP %1$d). %2$s', 'spidy-2fa-login' ),
				$code,
				$detail
			)
		);
	}
}
