<?php
/**
 * Smart Code Parser - Port from Fluent Security
 * Parses {{user.x}}, {{site.x}}, ##user.x##, ##site.x## in email templates.
 *
 * @package CustomWpEmails
 */

namespace CustomWpEmails\Includes;

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

class SmartCodeParser {

	/**
	 * Whether placeholders should use dummy values (preview/test sends).
	 */
	private function is_simulated_context(): bool {
		return defined( 'WPPS_PREVIEWING_EMAIL' ) || defined( 'WPPS_TESTING_EMAIL' );
	}

	public function parse( $template_string, $data ) {
		if ( ! $template_string ) {
			return $template_string;
		}
		$result = [];
		$is_single = ! is_array( $template_string );
		foreach ( (array) $template_string as $key => $string ) {
			$result[ $key ] = $this->parse_shortcode( $string, $data );
		}
		return $is_single ? reset( $result ) : $result;
	}

	public function parse_shortcode( $string, $data ) {
		if ( ! $string ) {
			return '';
		}
		if ( strpos( $string, '{{' ) === false && strpos( $string, '##' ) === false ) {
			return $string;
		}
		return preg_replace_callback( '/({{|##)+(.*?)(}}|##)/', function ( $matches ) use ( $data ) {
			return $this->replace( $matches, $data );
		}, $string );
	}

	protected function replace( $matches, $user ) {
		if ( empty( $matches[2] ) ) {
			return apply_filters( 'wpps_custom_wp_emails_smartcode_fallback', $matches[0], $user );
		}
		$matches[2] = trim( $matches[2] );
		$matched = explode( '.', $matches[2] );
		if ( count( $matched ) <= 1 ) {
			return apply_filters( 'wpps_custom_wp_emails_smartcode_fallback', $matches[0], $user );
		}
		$data_key  = trim( array_shift( $matched ) );
		$value_key = trim( implode( '.', $matched ) );
		if ( ! $value_key ) {
			return apply_filters( 'wpps_custom_wp_emails_smartcode_fallback', $matches[0], $user );
		}
		$value_keys   = explode( '|', $value_key );
		$value_key    = $value_keys[0];
		$default_val  = $value_keys[1] ?? '';
		$transformer  = $value_keys[2] ?? '';

		$value = '';
		switch ( $data_key ) {
			case 'site':
				$value = $this->get_site_value( $value_key, $default_val, $user );
				break;
			case 'user':
				$value = $user ? $this->get_user_value( $value_key, $default_val, $user ) : $default_val;
				break;
			default:
				$value = apply_filters( 'wpps_custom_wp_emails_smartcode_' . $data_key, $default_val, $value_key, $user );
		}

		if ( $transformer && $value ) {
			switch ( $transformer ) {
				case 'trim': $value = trim( $value ); break;
				case 'ucfirst': $value = ucfirst( $value ); break;
				case 'strtolower': $value = strtolower( $value ); break;
				case 'strtoupper': $value = strtoupper( $value ); break;
				case 'ucwords': $value = ucwords( $value ); break;
			}
		}
		$url_keys = [ 'password_reset_url', 'password_set_url', 'confirm_email_change_url', 'profile_edit_url', 'login_url', 'url' ];
		if ( in_array( $value_key, $url_keys, true ) && is_string( $value ) ) {
			return esc_url( $value );
		}
		return is_string( $value ) ? esc_html( $value ) : $value;
	}

	protected function get_site_value( $value_key, $default, $wp_user ) {
		if ( $value_key === 'login_url' ) {
			return network_site_url( 'wp-login.php', 'login' );
		}
		if ( $value_key === 'name' || $value_key === 'title' ) {
			return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
		}
		if ( $value_key === 'url' ) {
			return home_url();
		}
		if ( $value_key === 'admin_email' ) {
			return get_option( 'admin_email' );
		}
		$value = get_bloginfo( $value_key );
		return $value ?: $default;
	}

	protected function get_user_value( $value_key, $default, $wp_user ) {
		if ( ! $wp_user || ! $wp_user instanceof \WP_User ) {
			return $default;
		}
		if ( $value_key === 'password_reset_url' || $value_key === 'password_set_url' ) {
			if ( $this->is_simulated_context() ) {
				return '#password_reset_link_will_be_inserted_on_real_email';
			}
			$key = $wp_user->_password_reset_key_ ?? null;
			if ( ! $key ) {
				$key = get_password_reset_key( $wp_user );
			}
			if ( is_wp_error( $key ) ) {
				return $default;
			}
			return network_site_url( 'wp-login.php?action=rp&key=' . $key . '&login=' . rawurlencode( $wp_user->user_login ), 'login' );
		}
		if ( $value_key === 'new_changing_email_id' ) {
			if ( $this->is_simulated_context() ) {
				return 'new_email_will_be_inserted_on_real_email';
			}
			$meta = get_user_meta( $wp_user->ID, '_new_email', true );
			return is_array( $meta ) && isset( $meta['newemail'] ) ? $meta['newemail'] : $default;
		}
		if ( $value_key === 'confirm_email_change_url' ) {
			if ( $this->is_simulated_context() ) {
				return '#confirm_email_change_link_will_be_inserted_on_real_email';
			}
			$meta = get_user_meta( $wp_user->ID, '_new_email', true );
			$hash = is_array( $meta ) && isset( $meta['hash'] ) ? $meta['hash'] : '';
			return $hash ? esc_url( self_admin_url( 'profile.php?newuseremail=' . $hash ) ) : $default;
		}
		if ( $value_key === 'profile_edit_url' ) {
			return admin_url( 'user-edit.php?user_id=' . $wp_user->ID );
		}
		if ( $value_key === 'roles' ) {
			$roles = (array) ( $wp_user->roles ?? [] );
			return implode( ', ', array_map( 'ucfirst', $roles ) );
		}
		if ( $value_key === '_previous_email_address_' ) {
			return $wp_user->_previous_email_address_ ?? $default;
		}
		$value_keys = explode( '.', $value_key );
		if ( count( $value_keys ) === 1 ) {
			$value = $wp_user->get( $value_key );
			return ( $value && ! is_array( $value ) && ! is_object( $value ) ) ? $value : $default;
		}
		if ( $value_keys[0] === 'meta' ) {
			$meta = get_user_meta( $wp_user->ID, $value_keys[1], true );
			return ( $meta && ! is_array( $meta ) && ! is_object( $meta ) ) ? $meta : $default;
		}
		return $default;
	}
}
