<?php
/**
 * Avatars trait
 *
 * @package     AffiliateWP
 * @subpackage  Utils\Traits
 * @copyright   Copyright (c) 2025, Sandhills Development, LLC
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       2.34.0
 */

namespace AffiliateWP\Utils\Traits;

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

/**
 * Avatars trait
 *
 * Renders the avatar bubble shared by the affiliates list table, the Preview
 * Payout rows, and the payout drawer header: a Gravatar that fades in over an
 * always-present initials fallback, so a missing or 404 avatar leaves the
 * initials rather than a broken image or WP's mystery-person placeholder.
 *
 * @since 2.34.0
 */
trait Avatars {

	/**
	 * Render an avatar component.
	 *
	 * @since 2.34.0
	 *
	 * @param array $args {
	 *     Avatar arguments.
	 *
	 *     @type string     $name     Display name. Drives the initials fallback and is shown adjacent, so the image alt is left empty. Optional.
	 *     @type string|int $source   User ID or email passed to get_avatar_url() for the Gravatar lookup. Optional.
	 *     @type int        $size     Rendered diameter in px. Default 32.
	 *     @type string     $fallback Value to seed a single initial from (e.g. a username) when $name is empty. Optional.
	 *     @type string     $class    Additional CSS classes on the container. Optional.
	 * }
	 * @return string The rendered avatar HTML.
	 */
	public function render_avatar( $args = [] ) {

		$defaults = [
			'name'     => '',
			'source'   => '',
			'size'     => 32,
			'fallback' => '',
			'class'    => '',
		];

		$args = wp_parse_args( $args, $defaults );

		$size     = max( 1, (int) $args['size'] );
		$initials = affwp_get_initials_from_name( (string) $args['name'], (string) $args['fallback'] );

		// 404 (not a generic identicon) so the <img onerror> can fall back to the initials.
		$avatar_url = '';
		$source     = $args['source'];
		if ( '' !== (string) $source && '0' !== (string) $source ) {
			$avatar_url = get_avatar_url( $source, [ 'size' => $size * 2, 'default' => '404' ] );
		}

		$initials_html = '' !== $initials
			? sprintf(
				'<span class="font-semibold text-gray-500" style="font-size:%1$dpx">%2$s</span>',
				(int) round( $size * 0.34 ),
				esc_html( $initials )
			)
			: '';

		$img_html = $avatar_url
			? sprintf(
				'<img src="%1$s" alt="" class="absolute inset-0 rounded-full object-cover opacity-0" loading="lazy" onload="this.style.opacity=1" onerror="this.remove()">',
				esc_url( $avatar_url )
			)
			: '';

		$classes = trim( 'relative shrink-0 rounded-full bg-affwp-avatar-bg inline-flex items-center justify-center overflow-hidden ' . (string) $args['class'] );

		// Inline width/height: size is dynamic, so Tailwind's JIT can't generate a size-{n} class for it.
		return sprintf(
			'<span class="%1$s" style="width:%2$dpx;height:%2$dpx">%3$s%4$s</span>',
			esc_attr( $classes ),
			$size,
			$initials_html,
			$img_html
		);
	}
}
