<?php
/**
 * The warranty offer shown beside a product.
 *
 * @package WarrantyCart
 * @version 2.1.0
 */

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

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Template variables are local scope and don't need prefixing

/**
 * Template arguments.
 *
 * @var WC_Product             $product  The product being covered.
 * @var array<int, WC_Product> $offers   Warranty products on offer, cheapest first.
 * @var array<int, WC_Product> $included Warranty products that come free with it.
 * @var string                 $context  `product` or `cart`.
 */
$product  = $args['product'] ?? null;
$offers   = $args['offers'] ?? array();
$included = $args['included'] ?? array();
$context  = $args['context'] ?? 'product';

if ( ! $product instanceof WC_Product || ( empty( $offers ) && empty( $included ) ) ) {
	return;
}

/*
 * What comes with the product first, then what can be added to it.
 *
 * One list rather than two: the rows differ by a price and a button, and the
 * variation narrowing that hides a plan not covering the customer's choice has
 * to apply to both kinds equally.
 */
$rows = array();

foreach ( $included as $included_plan ) {
	$rows[] = array( $included_plan, true );
}

foreach ( $offers as $offered_plan ) {
	$rows[] = array( $offered_plan, false );
}

/*
 * Tags allowed in a price. `wc_price()` wraps every amount in `<bdi>` so a
 * price and its currency symbol keep their order inside right-to-left text, and
 * `wp_kses_post()` strips it. See templates/frontend/warranty-selector.php.
 */
$warranty_price_tags = array(
	'span' => array(
		'class'     => true,
		'translate' => true,
	),
	'bdi'  => array(),
	'del'  => array(),
	'ins'  => array(),
);

$offer_id = 'warranty-offer-' . $context . '-' . $product->get_id();

/*
 * A variable product does not say what it costs until a variation is chosen.
 *
 * Its `get_price()` is the cheapest variation's, so a percentage plan quoted
 * from it prices the whole range at the price of its cheapest member. The offer
 * therefore waits: it shows the range, and the buttons stay disabled until the
 * customer has picked the thing being covered. That also keeps the record
 * honest, since what gets covered is a variation and not the parent.
 */
$is_variable = $product->is_type( 'variable' );
?>

<div
	class="warranty-offer warranty-offer--<?php echo \esc_attr( $context ); ?>"
	id="<?php echo \esc_attr( $offer_id ); ?>"
	data-covered="<?php echo \esc_attr( (string) $product->get_id() ); ?>"
	<?php if ( $is_variable ) : ?>
		data-variable="1"
	<?php endif; ?>
>
	<div class="warranty-offer__head">
		<h3 class="warranty-offer__title">
			<?php
			/*
			 * A heading that says what the block is for.
			 *
			 * "Add protection" over a list of cover the customer already has
			 * reads as a charge they are about to be asked for.
			 */
			if ( empty( $offers ) ) {
				\esc_html_e( 'Cover included', 'warranty-cart' );
			} elseif ( 'cart' === $context ) {
				printf(
					/* translators: %s: product name. */
					\esc_html__( 'Protect your %s', 'warranty-cart' ),
					\esc_html( $product->get_name() )
				);
			} else {
				\esc_html_e( 'Add protection', 'warranty-cart' );
			}
			?>
		</h3>
	</div>

	<?php /* Where the offer reports success or failure. */ ?>
	<div class="warranty-offer__notice" role="status" aria-live="polite" hidden></div>

	<ul class="warranty-offer__list">
		<?php foreach ( $rows as $row ) : ?>
			<?php
			list( $offer, $is_included ) = $row;

			$coverage = (string) $offer->get_meta( '_warranty_cart_coverage_details', true );
			$duration = (int) $offer->get_meta( '_warranty_cart_duration', true );
			$unit     = (string) $offer->get_meta( '_warranty_cart_duration_unit', true );

			/*
			 * What this plan costs against each variation.
			 *
			 * Rendered as price HTML rather than as numbers, because formatting
			 * money is the store's job: decimal places, separators and the side
			 * the symbol sits on all vary by currency, and a second
			 * implementation in JavaScript would disagree with the cart. This is
			 * how WooCommerce ships its own variation prices.
			 *
			 * Empty for a fixed-price plan, whose price is the same whichever
			 * variation is chosen.
			 */
			$variation_prices = \WarrantyCart\Core\Pricing::variation_prices( $offer, $product );
			$variation_markup = array();

			foreach ( $variation_prices as $variation_id => $variation_price ) {
				$variation_markup[ $variation_id ] = \wc_price( $variation_price );
			}

			/*
			 * Which variations this plan covers, where the rule names some and
			 * not others. Carried to the page because the offer is rendered
			 * before the customer has chosen, and the answer differs per choice.
			 */
			$covered_variations = $is_variable
				? \WarrantyCart\Core\Coverage::covered_variations( $offer, $product )
				: array();
			?>
			<li
				class="warranty-offer__item<?php echo $is_included ? ' warranty-offer__item--included' : ''; ?>"
				<?php if ( $variation_markup ) : ?>
					data-prices="<?php echo \esc_attr( (string) \wp_json_encode( $variation_markup ) ); ?>"
				<?php endif; ?>
				<?php if ( $covered_variations ) : ?>
					data-variations="<?php echo \esc_attr( (string) \wp_json_encode( $covered_variations ) ); ?>"
				<?php endif; ?>
			>
				<?php
				/*
				 * The plan's own image, when it has one. Optional by design:
				 * most shops sell cover without a picture, and a placeholder box
				 * beside every row would be a column of grey squares.
				 */
				$offer_image = $offer->get_image_id()
					? \wp_get_attachment_image(
						$offer->get_image_id(),
						'woocommerce_gallery_thumbnail',
						false,
						array(
							'class'   => 'warranty-offer__image',
							'alt'     => '',
							'loading' => 'lazy',
						)
					)
					: '';
				?>
				<?php if ( $offer_image ) : ?>
					<?php echo \wp_kses_post( $offer_image ); ?>
				<?php endif; ?>

				<div class="warranty-offer__detail">
					<span class="warranty-offer__name"><?php echo \esc_html( $offer->get_name() ); ?></span>

					<?php if ( $coverage ) : ?>
						<span class="warranty-offer__coverage">
							<?php echo \esc_html( str_replace( "\n", ' · ', $coverage ) ); ?>
						</span>
					<?php endif; ?>
				</div>

				<span class="warranty-offer__price">
					<?php
					if ( $is_included ) {
						/*
						 * No price, and no struck-through one either. Cover the
						 * shop always gave away was never worth what a fake
						 * "was £49" would claim, and printing one invites the
						 * question of what it costs to decline.
						 */
						\esc_html_e( 'Included', 'warranty-cart' );
					} else {
						/*
						 * The price against this product, not the warranty's own.
						 *
						 * A percentage warranty's product price is a fallback for
						 * pages where nothing is being covered; showing it here
						 * would quote the customer a figure they will not be
						 * charged.
						 *
						 * A range where the covered product has variations that
						 * would be charged differently. Quoting the bottom of that
						 * range as though it were the price is the bug this
						 * replaced: it is true of one variation and undercharges
						 * for every other.
						 */
						$offer_price = \wc_price( \WarrantyCart\Core\Pricing::price( $offer, $product ) );

						if ( count( $variation_prices ) > 1 && min( $variation_prices ) !== max( $variation_prices ) ) {
							$offer_price = \wc_format_price_range( min( $variation_prices ), max( $variation_prices ) );
						}

						echo \wp_kses( $offer_price, $warranty_price_tags );
					}
					?>
				</span>

				<?php if ( ! $is_included ) : ?>
					<button
						type="button"
						class="button warranty-offer__add"
						data-warranty="<?php echo \esc_attr( (string) $offer->get_id() ); ?>"
						<?php /* Filled in by the variation the customer chooses. */ ?>
						data-covered="<?php echo $is_variable ? '' : \esc_attr( (string) $product->get_id() ); ?>"
						<?php if ( $duration > 0 ) : ?>
							data-term="<?php echo \esc_attr( $duration . ' ' . $unit ); ?>"
						<?php endif; ?>
						<?php disabled( $is_variable ); ?>
					>
						<?php \esc_html_e( 'Add cover', 'warranty-cart' ); ?>
					</button>
				<?php endif; ?>
			</li>
		<?php endforeach; ?>
	</ul>

	<?php if ( $is_variable ) : ?>
		<p class="warranty-offer__hint">
			<?php
			// Nothing is being sold, so there is no price to wait for — but which
			// cover applies still depends on the option chosen.
			if ( empty( $offers ) ) {
				\esc_html_e( 'Choose your options above to see the cover included.', 'warranty-cart' );
			} else {
				\esc_html_e( 'Choose your options above to see the price of cover.', 'warranty-cart' );
			}
			?>
		</p>
	<?php endif; ?>
</div>
