<?php
/**
 * Email Placeholder Replacement.
 *
 * Handles dynamic placeholder replacement in email subject and body.
 *
 * @package Ugcify\Email
 */

namespace Ugcify\Email;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class EmailPlaceholders
 */
class EmailPlaceholders {

	/**
	 * Replace placeholders in content with actual data.
	 *
	 * @param string $content The content containing placeholders.
	 * @param array  $data    Key-value pairs of placeholder data.
	 * @return string Content with placeholders replaced.
	 */
	public static function replace( $content, array $data ) {
		// Build search/replace arrays from data.
		$search  = array();
		$replace = array();

		foreach ( $data as $key => $value ) {
			// Support both {key} and key formats.
			$placeholder = '{' . ltrim( rtrim( $key, '}' ), '{' ) . '}';
			$search[]    = $placeholder;
			$replace[]   = (string) $value;
		}

		// Always include {site_name} if not provided.
		if ( ! in_array( '{site_name}', $search, true ) ) {
			$search[]  = '{site_name}';
			$replace[] = get_bloginfo( 'name' );
		}

		return str_replace( $search, $replace, $content );
	}

	/**
	 * Build placeholder data for order-related emails.
	 *
	 * @param \WC_Order $order WooCommerce order object.
	 * @return array Placeholder data.
	 */
	public static function build_order_data( $order ) {
		$data = array(
			'user_name'  => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
			'user_email' => $order->get_billing_email(),
			'order_id'   => $order->get_id(),
			'site_name'  => get_bloginfo( 'name' ),
		);

		// Get product names and links from order items.
		$product_names = array();
		$product_links = array();
		$review_items  = array();
		foreach ( $order->get_items() as $item ) {
			$product_names[] = $item->get_name();
			$product = $item->get_product();
			if ( $product ) {
				$product_url = self::get_product_url( $product->get_id() );
				$product_links[] = '<a href="' . esc_url( $product_url ) . '">' . esc_html( $item->get_name() ) . '</a>';
			} else {
				$product_links[] = esc_html( $item->get_name() );
			}

			$review_items[] = self::build_order_review_item_data( $item, $product );
		}
		$data['product_name'] = implode( ', ', $product_names );
		$data['product_link'] = implode( ', ', $product_links );
		$data['review_url']   = isset( $review_items[0] ) ? $review_items[0]['review_url'] : '';
		$data['order_products_review_table'] = self::build_order_products_review_table( $review_items );
		$data['order_review_cta']            = self::build_order_review_cta( $review_items );

		return $data;
	}

	/**
	 * Build normalized order item data for review request emails.
	 *
	 * @param object       $item    WooCommerce order item object.
	 * @param object|false $product WooCommerce product object when available.
	 * @return array
	 */
	private static function build_order_review_item_data( $item, $product ) {
		$product_id = 0;
		if ( $product && method_exists( $product, 'get_id' ) ) {
			$product_id = absint( $product->get_id() );
		} elseif ( method_exists( $item, 'get_product_id' ) ) {
			$product_id = absint( $item->get_product_id() );
		}

		$image_id = ( $product && method_exists( $product, 'get_image_id' ) ) ? absint( $product->get_image_id() ) : 0;
		$quantity = method_exists( $item, 'get_quantity' ) ? absint( $item->get_quantity() ) : 1;
		if ( $quantity < 1 ) {
			$quantity = 1;
		}

		$product_url = $product_id > 0 ? self::get_product_url( $product_id ) : '';

		return array(
			'name'        => method_exists( $item, 'get_name' ) ? $item->get_name() : __( 'Product', 'ugcify' ),
			'quantity'    => $quantity,
			'product_url' => $product_url,
			'review_url'  => $product_url ? self::get_review_url( $product_url ) : '',
			'image_url'   => self::get_product_image_url( $image_id ),
		);
	}

	/**
	 * Build adaptive order review CTA HTML.
	 *
	 * @param array $items Normalized order item data.
	 * @return string
	 */
	private static function build_order_review_cta( array $items ) {
		if ( empty( $items ) ) {
			return '';
		}

		if ( 1 === count( $items ) ) {
			return self::build_single_product_review_cta( $items[0] );
		}

		return self::build_order_products_review_table( $items );
	}

	/**
	 * Build single-product review CTA with order detail context.
	 *
	 * @param array $item Normalized order item data.
	 * @return string
	 */
	private static function build_single_product_review_cta( array $item ) {
		$html = '<div style="margin:24px 0;padding:16px;border:1px solid #e5e7eb;border-radius:8px;background:#fafafa;">';
		$html .= '<p style="margin:0 0 12px;font-weight:600;color:#1f2937;">' . esc_html__( 'Your order details', 'ugcify' ) . '</p>';
		$html .= '<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="width:100%;border-collapse:collapse;margin:0 0 16px;">';
		$html .= '<tr>';
		$html .= '<td style="width:68px;padding:0 12px 0 0;vertical-align:middle;">' . self::build_product_image_html( $item ) . '</td>';
		$html .= '<td style="padding:0;vertical-align:middle;">';
		$html .= '<p style="margin:0 0 4px;"><strong>' . esc_html__( 'Product:', 'ugcify' ) . '</strong> ' . self::build_product_name_html( $item ) . '</p>';
		$html .= '<p style="margin:0;color:#555;"><strong>' . esc_html__( 'Quantity:', 'ugcify' ) . '</strong> ' . esc_html( (string) $item['quantity'] ) . '</p>';
		$html .= '</td>';
		$html .= '</tr>';
		$html .= '</table>';
		$html .= '<p style="text-align:center;margin:0;">' . self::build_review_button( $item['review_url'] ) . '</p>';
		$html .= '</div>';

		return $html;
	}

	/**
	 * Build multi-product review table HTML.
	 *
	 * @param array $items Normalized order item data.
	 * @return string
	 */
	private static function build_order_products_review_table( array $items ) {
		if ( count( $items ) < 2 ) {
			return '';
		}

		$html = '<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="width:100%;border-collapse:collapse;margin:24px 0;border:1px solid #e5e7eb;">';
		$html .= '<thead><tr>';
		$html .= '<th style="padding:10px;border-bottom:1px solid #e5e7eb;text-align:left;font-size:13px;">' . esc_html__( 'Product Image', 'ugcify' ) . '</th>';
		$html .= '<th style="padding:10px;border-bottom:1px solid #e5e7eb;text-align:left;font-size:13px;">' . esc_html__( 'Product Name', 'ugcify' ) . '</th>';
		$html .= '<th style="padding:10px;border-bottom:1px solid #e5e7eb;text-align:left;font-size:13px;">' . esc_html__( 'Product count', 'ugcify' ) . '</th>';
		$html .= '<th style="padding:10px;border-bottom:1px solid #e5e7eb;text-align:left;font-size:13px;">' . esc_html__( 'Review Button', 'ugcify' ) . '</th>';
		$html .= '</tr></thead><tbody>';

		foreach ( $items as $item ) {
			$html .= '<tr>';
			$html .= '<td style="padding:10px;border-bottom:1px solid #e5e7eb;vertical-align:middle;">' . self::build_product_image_html( $item ) . '</td>';
			$html .= '<td style="padding:10px;border-bottom:1px solid #e5e7eb;vertical-align:middle;">' . self::build_product_name_html( $item ) . '</td>';
			$html .= '<td style="padding:10px;border-bottom:1px solid #e5e7eb;vertical-align:middle;">' . esc_html( (string) $item['quantity'] ) . '</td>';
			$html .= '<td style="padding:10px;border-bottom:1px solid #e5e7eb;vertical-align:middle;">' . self::build_review_button( $item['review_url'] ) . '</td>';
			$html .= '</tr>';
		}

		$html .= '</tbody></table>';

		return $html;
	}

	/**
	 * Build product image cell HTML.
	 *
	 * @param array $item Normalized order item data.
	 * @return string
	 */
	private static function build_product_image_html( array $item ) {
		if ( empty( $item['image_url'] ) ) {
			return '<span style="color:#999;">&mdash;</span>';
		}

		return '<img src="' . esc_url( $item['image_url'] ) . '" alt="' . esc_attr( $item['name'] ) . '" width="56" height="56" style="width:56px;height:56px;object-fit:cover;border-radius:4px;display:block;">';
	}

	/**
	 * Build product name cell HTML.
	 *
	 * @param array $item Normalized order item data.
	 * @return string
	 */
	private static function build_product_name_html( array $item ) {
		if ( empty( $item['product_url'] ) ) {
			return esc_html( $item['name'] );
		}

		return '<a href="' . esc_url( $item['product_url'] ) . '">' . esc_html( $item['name'] ) . '</a>';
	}

	/**
	 * Build review button HTML.
	 *
	 * @param string $review_url Direct review URL.
	 * @return string
	 */
	private static function build_review_button( $review_url ) {
		if ( empty( $review_url ) ) {
			return '';
		}

		return '<a href="' . esc_url( $review_url ) . '" style="background:#201CFE;color:#fff;text-decoration:none;padding:6px 10px;border-radius:5px;font-size:12px;line-height:1.2;font-weight:600;display:inline-block;white-space:nowrap;">' . esc_html__( 'Submit a Review', 'ugcify' ) . '</a>';
	}

	/**
	 * Get product permalink.
	 *
	 * @param int $product_id Product ID.
	 * @return string
	 */
	private static function get_product_url( $product_id ) {
		$url = get_permalink( $product_id );
		return $url ? (string) $url : '';
	}

	/**
	 * Add review auto-open query arg to product URL.
	 *
	 * @param string $product_url Product URL.
	 * @return string
	 */
	private static function get_review_url( $product_url ) {
		if ( function_exists( 'add_query_arg' ) ) {
			return add_query_arg( 'ugcify_open_review', '1', $product_url );
		}

		$separator = false === strpos( $product_url, '?' ) ? '?' : '&';
		return $product_url . $separator . 'ugcify_open_review=1';
	}

	/**
	 * Get product thumbnail URL for email table.
	 *
	 * @param int $image_id Attachment ID.
	 * @return string
	 */
	private static function get_product_image_url( $image_id ) {
		if ( $image_id < 1 || ! function_exists( 'wp_get_attachment_image_url' ) ) {
			return '';
		}

		$image_url = wp_get_attachment_image_url( $image_id, 'thumbnail' );
		return $image_url ? (string) $image_url : '';
	}

	/**
	 * Build placeholder data for review-related emails.
	 *
	 * @param array $review    Review data array.
	 * @param int   $review_id Optional review ID for generating admin links.
	 * @return array Placeholder data.
	 */
	public static function build_review_data( $review, $review_id = 0 ) {
		$data = array(
			'site_name'      => get_bloginfo( 'name' ),
			'review_content' => isset( $review['content'] ) ? wp_strip_all_tags( $review['content'] ) : '',
			'review_rating'  => isset( $review['rating'] ) ? $review['rating'] : '',
		);

		// Resolve user info from review data.
		if ( ! empty( $review['user_id'] ) ) {
			$user = get_user_by( 'id', $review['user_id'] );
			if ( $user ) {
				$data['user_name']  = $user->display_name;
				$data['user_email'] = $user->user_email;
			}
		}

		// Fallback to guest info.
		if ( empty( $data['user_name'] ) ) {
			$data['user_name'] = ! empty( $review['guest_name'] ) ? $review['guest_name'] : __( 'Customer', 'ugcify' );
		}
		if ( empty( $data['user_email'] ) ) {
			$data['user_email'] = ! empty( $review['guest_email'] ) ? $review['guest_email'] : '';
		}

		// Resolve product name and link.
		if ( ! empty( $review['product_id'] ) ) {
			$product_title = get_the_title( $review['product_id'] );
			$data['product_name'] = $product_title ? $product_title : __( 'Product', 'ugcify' );
			$product_url = get_permalink( $review['product_id'] );
			if ( $product_url ) {
				$data['product_link'] = '<a href="' . esc_url( $product_url ) . '">' . esc_html( $data['product_name'] ) . '</a>';
			} else {
				$data['product_link'] = esc_html( $data['product_name'] );
			}
		} else {
			$data['product_name'] = __( 'Product', 'ugcify' );
			$data['product_link'] = __( 'Product', 'ugcify' );
		}

		// Add review admin link if review_id is provided.
		if ( $review_id > 0 ) {
			$admin_url = admin_url( 'admin.php?page=ugcify#/contents/' . $review_id );
			$data['review_link'] = '<a href="' . esc_url( $admin_url ) . '">' . __( 'View Review', 'ugcify' ) . '</a>';
		} else {
			$data['review_link'] = '';
		}

		return $data;
	}

	/**
	 * Build placeholder data for a reward-bearing review approval email.
	 *
	 * @param array $review         Review data array.
	 * @param int   $review_id      Review ID.
	 * @param int   $user_id        Rewarded user ID.
	 * @param int   $points_awarded Exact points awarded for the approval.
	 * @return array
	 */
	public static function build_review_reward_data( array $review, int $review_id, int $user_id, int $points_awarded ): array {
		$data  = self::build_review_data( $review, $review_id );
		$state = self::build_reward_state_data( $user_id );

		$data['points_earned']  = (string) absint( $points_awarded );
		$data['reward_message'] = self::build_reward_message_html( absint( $points_awarded ), $state['available_balance'] );

		return array_merge( $data, $state );
	}

	/**
	 * Build placeholder data for a featured review bonus email.
	 *
	 * @param array $review         Review data array.
	 * @param int   $review_id      Review ID.
	 * @param int   $user_id        Rewarded user ID.
	 * @param int   $points_awarded Exact featured bonus awarded.
	 * @return array
	 */
	public static function build_featured_reward_data( array $review, int $review_id, int $user_id, int $points_awarded ): array {
		$data = self::build_review_reward_data( $review, $review_id, $user_id, $points_awarded );
		unset( $data['reward_message'] );

		return $data;
	}

	/**
	 * Build placeholder data for a lightbox purchase reward email.
	 *
	 * @param array $review         Review data array.
	 * @param int   $review_id      Review ID.
	 * @param int   $user_id        Rewarded user ID.
	 * @param int   $order_id       Completed order ID.
	 * @param int   $points_awarded Exact referral bonus awarded.
	 * @return array
	 */
	public static function build_lightbox_purchase_reward_data( array $review, int $review_id, int $user_id, int $order_id, int $points_awarded ): array {
		$data             = self::build_review_reward_data( $review, $review_id, $user_id, $points_awarded );
		$data['order_id'] = $order_id > 0 ? (string) $order_id : '';
		unset( $data['reward_message'] );

		return $data;
	}

	/**
	 * Build placeholder data for a points redeemed email.
	 *
	 * @param int    $user_id         Rewarded user ID.
	 * @param int    $points_redeemed Exact points deducted.
	 * @param string $description     Human-readable redemption description.
	 * @param array  $meta            Optional redemption metadata.
	 * @return array
	 */
	public static function build_points_redeemed_data( int $user_id, int $points_redeemed, string $description, array $meta = array() ): array {
		$data = array_merge(
			self::build_registered_user_data( $user_id ),
			self::build_reward_state_data( $user_id )
		);

		$data['points_redeemed']       = (string) absint( $points_redeemed );
		$data['redemption_description'] = wp_strip_all_tags( $description );
		$data['order_id']              = ! empty( $meta['order_id'] ) ? (string) absint( $meta['order_id'] ) : '';
		$data['discount_amount']       = self::format_discount_amount( $meta['discount'] ?? null );

		return $data;
	}

	/**
	 * Build placeholder data for a badge gain or upgrade email.
	 *
	 * @param int   $user_id Rewarded user ID.
	 * @param array $payload Badge update payload.
	 * @return array
	 */
	public static function build_badge_update_data( int $user_id, array $payload ): array {
		$data = array_merge(
			self::build_registered_user_data( $user_id ),
			self::build_reward_state_data( $user_id )
		);

		$change_type = self::normalize_badge_change_type( (string) ( $payload['change_type'] ?? 'gained' ) );
		$previous    = trim( (string) ( $payload['previous_badge'] ?? '' ) );
		$current     = trim( (string) ( $payload['current_badge'] ?? '' ) );

		$data['previous_badge']        = '' !== $previous ? self::format_badge_label( $previous ) : __( 'No badge yet', 'ugcify' );
		$data['current_badge']         = '' !== $current ? self::format_badge_label( $current ) : $data['current_badge'];
		$data['approved_review_count'] = (string) absint( $payload['approved_review_count'] ?? 0 );
		$data['badge_change_type']     = self::format_badge_change_type( $change_type );
		$data['badge_update_message']  = self::build_badge_update_message( $change_type, $data['previous_badge'], $data['current_badge'] );

		return $data;
	}

	/**
	 * Build common registered-user placeholder data.
	 *
	 * @param int $user_id WordPress user ID.
	 * @return array
	 */
	private static function build_registered_user_data( int $user_id ): array {
		$data = array(
			'site_name'  => get_bloginfo( 'name' ),
			'user_name'  => __( 'Customer', 'ugcify' ),
			'user_email' => '',
		);

		if ( $user_id <= 0 ) {
			return $data;
		}

		$user = get_user_by( 'id', $user_id );
		if ( $user ) {
			$data['user_name']  = $user->display_name;
			$data['user_email'] = $user->user_email;
		}

		return $data;
	}

	/**
	 * Build shared reward-state placeholders.
	 *
	 * @param int $user_id WordPress user ID.
	 * @return array
	 */
	private static function build_reward_state_data( int $user_id ): array {
		$state = array(
			'current_tier'      => self::format_tier_label( 'guest' ),
			'current_badge'     => __( 'No badge yet', 'ugcify' ),
			'available_balance' => '0',
		);

		if ( $user_id <= 0 ) {
			return $state;
		}

		/**
		 * Short-circuit the reward state lookup.
		 *
		 * Return a non-null array to skip the default PointsManager/RewardSettingsAPI
		 * lookup. Array keys: 'summary' (array), 'settings' (array).
		 *
		 * @param array|null $override null by default.
		 * @param int        $user_id  User ID.
		 */
		$override = function_exists( 'apply_filters' )
			? apply_filters( 'ugcify_email_reward_state_source', null, $user_id )
			: null;

		if ( is_array( $override ) ) {
			$summary  = isset( $override['summary'] ) && is_array( $override['summary'] ) ? $override['summary'] : array();
			$settings = isset( $override['settings'] ) && is_array( $override['settings'] ) ? $override['settings'] : array();
		} else {
			$manager  = new \Ugcify\Points\PointsManager();
			$summary  = $manager->get_user_summary( $user_id, false );
			$settings = \Ugcify\Admin\API\RewardSettingsAPI::get_reward_settings();
		}

		$state['available_balance'] = (string) absint( $summary['available_balance'] ?? 0 );
		$state['current_tier']      = self::format_tier_label( $summary['current_tier'] ?? 'guest' );

		$badge_name = self::resolve_current_badge_name( $user_id, $summary, $settings );
		if ( '' !== $badge_name ) {
			$state['current_badge'] = $badge_name;
		}

		return $state;
	}

	/**
	 * Resolve the current display badge name for a user.
	 *
	 * @param int   $user_id  WordPress user ID.
	 * @param array $summary  Current reward summary.
	 * @param array $settings Reward settings.
	 * @return string
	 */
	private static function resolve_current_badge_name( int $user_id, array $summary, array $settings ): string {
		$raw_badge  = (string) ( $summary['current_badge'] ?? '' );
		$badge_name = '';

		if ( class_exists( '\\Ugcify\\Rewards\\BadgeResolver' ) ) {
			$badge_info = \Ugcify\Rewards\BadgeResolver::resolve_display_badge( $user_id, $summary, $settings );
			if ( ! empty( $badge_info['name'] ) ) {
				$badge_name = (string) $badge_info['name'];
			}
		}

		if ( '' !== $badge_name ) {
			return $badge_name;
		}

		return '' !== $raw_badge ? self::format_badge_label( $raw_badge ) : '';
	}

	/**
	 * Build a reusable reward summary HTML block.
	 *
	 * @param int    $points_awarded    Exact points awarded.
	 * @param string $available_balance Current available balance.
	 * @return string
	 */
	private static function build_reward_message_html( int $points_awarded, string $available_balance ): string {
		if ( $points_awarded <= 0 ) {
			return '';
		}

		$message  = '<div style="background-color: #f0f9f0; border: 1px solid #c3e6c3; border-radius: 6px; padding: 20px; margin: 20px 0; text-align: center;">';
		$message .= '<p style="font-size: 16px; font-weight: bold; color: #2d6a2d; margin: 0 0 10px 0;">';
		$message .= __( 'UGC Reward added to your account', 'ugcify' );
		$message .= '</p>';
		$message .= '<p style="font-size: 14px; color: #555; margin: 0 0 10px 0;">';
		$message .= sprintf(
			/* translators: 1: earned points, 2: available balance */
			__( 'You earned %1$d reward points. Your available balance is now %2$s pts.', 'ugcify' ),
			$points_awarded,
			$available_balance
		);
		$message .= '</p>';
		$message .= '<p style="font-size: 28px; font-weight: bold; color: #2d6a2d; margin: 0;">';
		$message .= sprintf(
			/* translators: %d: number of points */
			__( '+%d pts', 'ugcify' ),
			$points_awarded
		);
		$message .= '</p>';
		$message .= '</div>';

		return $message;
	}

	private static function normalize_badge_change_type( string $change_type ): string {
		return 'upgraded' === strtolower( $change_type ) ? 'upgraded' : 'gained';
	}

	private static function format_badge_change_type( string $change_type ): string {
		return 'upgraded' === $change_type ? __( 'Upgraded', 'ugcify' ) : __( 'Gained', 'ugcify' );
	}

	private static function build_badge_update_message( string $change_type, string $previous_badge, string $current_badge ): string {
		if ( 'upgraded' === $change_type ) {
			return sprintf(
				/* translators: 1: previous badge name, 2: current badge name */
				__( 'You upgraded your badge from %1$s to %2$s.', 'ugcify' ),
				$previous_badge,
				$current_badge
			);
		}

		return sprintf(
			/* translators: %s: badge name */
			__( 'You earned your first contribution badge: %s.', 'ugcify' ),
			$current_badge
		);
	}

	/**
	 * Format a tier slug into a human-readable label.
	 *
	 * @param string $tier Tier slug.
	 * @return string
	 */
	private static function format_tier_label( string $tier ): string {
		$labels = array(
			'guest'       => __( 'Guest', 'ugcify' ),
			'newcomer'    => __( 'Newcomer', 'ugcify' ),
			'contributor' => __( 'Contributor', 'ugcify' ),
			'advocate'    => __( 'Advocate', 'ugcify' ),
			'champion'    => __( 'Champion', 'ugcify' ),
		);

		return $labels[ $tier ] ?? ucwords( str_replace( array( '-', '_' ), ' ', $tier ) );
	}

	/**
	 * Format a badge slug into a human-readable label.
	 *
	 * @param string $badge Badge slug or name.
	 * @return string
	 */
	private static function format_badge_label( string $badge ): string {
		$labels = array(
			'bronze'   => __( 'Bronze', 'ugcify' ),
			'silver'   => __( 'Silver', 'ugcify' ),
			'gold'     => __( 'Gold', 'ugcify' ),
			'platinum' => __( 'Platinum', 'ugcify' ),
		);

		return $labels[ $badge ] ?? ucwords( str_replace( array( '-', '_' ), ' ', $badge ) );
	}

	/**
	 * Format a redemption discount amount.
	 *
	 * @param mixed $discount Discount amount.
	 * @return string
	 */
	private static function format_discount_amount( $discount ): string {
		if ( null === $discount || '' === $discount ) {
			return '';
		}

		$amount = (float) $discount;
		if ( function_exists( 'wc_price' ) ) {
			return wp_strip_all_tags( wc_price( $amount ) );
		}

		$currency = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol() : '';
		return $currency . number_format( $amount, 2 );
	}
}
