<?php
/**
 * Shared front-end product view helpers.
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\Frontend;

use WPDude\Products\Products\Post_Type;
use WPDude\Products\Products\Product_Meta;
use WPDude\Products\Products\Stock_Service;
use WPDude\Products\Support\Money;

/**
 * Resolve product display data for shortcodes/blocks.
 */
final class Product_View {

	/**
	 * HTML id / URL fragment for a product section (Stripe return scroll target).
	 */
	public static function section_anchor( int $product_id ): string {
		$product_id = absint( $product_id );
		return $product_id > 0 ? 'wpdude-dc-product-' . $product_id : '';
	}

	/**
	 * Published product or null.
	 */
	public static function get_product( int $product_id ): ?\WP_Post {
		$product = get_post( $product_id );
		if ( ! $product || Post_Type::POST_TYPE !== $product->post_type || 'publish' !== $product->post_status ) {
			return null;
		}
		return $product;
	}

	/**
	 * Featured image URL (large).
	 */
	public static function featured_url( int $product_id, string $size = 'large' ): string {
		$url = get_the_post_thumbnail_url( $product_id, $size );
		return is_string( $url ) ? $url : '';
	}

	/**
	 * Gallery attachment URLs (medium).
	 *
	 * @return list<array{id: int, url: string, thumb: string}>
	 */
	public static function gallery_items( int $product_id ): array {
		$items = array();
		foreach ( Product_Meta::get_gallery( $product_id ) as $id ) {
			$id  = (int) $id;
			$url = wp_get_attachment_image_url( $id, 'large' );
			$th  = wp_get_attachment_image_url( $id, 'thumbnail' );
			if ( ! is_string( $url ) || '' === $url ) {
				continue;
			}
			$items[] = array(
				'id'    => $id,
				'url'   => $url,
				'thumb' => is_string( $th ) ? $th : $url,
			);
		}
		return $items;
	}

	/**
	 * Combination map for JS (key => price/image/stock/on_sale).
	 *
	 * @return array<string, array{price_minor: int, price_formatted: string, image_id: int, image_url: string, image_thumb: string, stock: int, on_sale: bool}>
	 */
	public static function combination_map( int $product_id ): array {
		$currency = Product_Meta::get_currency( $product_id );
		$map      = array();
		foreach ( Product_Meta::get_combinations( $product_id ) as $combo ) {
			$key = (string) ( $combo['key'] ?? '' );
			if ( '' === $key ) {
				continue;
			}
			$price       = Stock_Service::unit_price_minor( $product_id, $key );
			$image_id    = (int) ( $combo['image_id'] ?? 0 );
			$image_url   = '';
			$image_thumb = '';
			if ( $image_id > 0 ) {
				$url = wp_get_attachment_image_url( $image_id, 'large' );
				$th  = wp_get_attachment_image_url( $image_id, 'thumbnail' );
				$image_url   = is_string( $url ) ? $url : '';
				$image_thumb = is_string( $th ) ? $th : $image_url;
			}
			$map[ $key ] = array(
				'price_minor'     => $price,
				'price_formatted' => Money::format( $price, $currency ),
				'image_id'        => $image_id,
				'image_url'       => $image_url,
				'image_thumb'     => $image_thumb,
				'stock'           => max( 0, (int) ( $combo['stock'] ?? 0 ) ),
				'on_sale'         => Product_Meta::combination_is_on_sale( $combo ),
			);
		}
		return $map;
	}

	/**
	 * Lowest combination unit price (options products), or 0.
	 */
	public static function lowest_combination_price_minor( int $product_id ): int {
		$lowest = 0;
		foreach ( self::combination_map( $product_id ) as $row ) {
			$price = (int) ( $row['price_minor'] ?? 0 );
			if ( $price <= 0 ) {
				continue;
			}
			if ( 0 === $lowest || $price < $lowest ) {
				$lowest = $price;
			}
		}
		return $lowest;
	}

	/**
	 * Default price label (standard price, or “From …” for options).
	 */
	public static function default_price_formatted( int $product_id ): string {
		$currency = Product_Meta::get_currency( $product_id );

		if ( Product_Meta::TYPE_OPTIONS === Product_Meta::get_type( $product_id ) ) {
			$lowest = self::lowest_combination_price_minor( $product_id );
			if ( $lowest <= 0 ) {
				return Money::format( 0, $currency );
			}
			return sprintf(
				/* translators: %s: formatted money amount */
				__( 'Prices from %s', 'dude-commerce' ),
				Money::format( $lowest, $currency )
			);
		}

		return Money::format(
			Product_Meta::get_effective_price_minor( $product_id ),
			$currency
		);
	}

	/**
	 * Render images markup.
	 */
	public static function render_images( int $product_id ): string {
		$featured = self::featured_url( $product_id );
		$gallery  = self::gallery_items( $product_id );
		$map      = self::combination_map( $product_id );
		$main     = $featured;
		if ( '' === $main && ! empty( $gallery ) ) {
			$main = $gallery[0]['url'];
		}

		// Unique combination images not already in featured/gallery.
		$seen_urls   = array();
		$combo_thumbs = array();
		if ( '' !== $featured ) {
			$seen_urls[ $featured ] = true;
		}
		foreach ( $gallery as $item ) {
			$seen_urls[ $item['url'] ] = true;
		}
		foreach ( $map as $combo_key => $row ) {
			$url = (string) ( $row['image_url'] ?? '' );
			if ( '' === $url || isset( $seen_urls[ $url ] ) ) {
				continue;
			}
			$seen_urls[ $url ] = true;
			$combo_thumbs[]    = array(
				'key'   => (string) $combo_key,
				'url'   => $url,
				'thumb' => (string) ( $row['image_thumb'] ?? $url ),
			);
		}

		$combo_json = wp_json_encode( $map );
		if ( ! is_string( $combo_json ) ) {
			$combo_json = '{}';
		}

		$show_thumbs = '' !== $featured || count( $gallery ) > 0 || count( $combo_thumbs ) > 0;
		// Avoid a lone duplicate of the main image when there is nothing else to pick.
		if ( $show_thumbs && '' !== $featured && empty( $gallery ) && empty( $combo_thumbs ) ) {
			$show_thumbs = false;
		}

		ob_start();
		?>
		<div
			class="wpdude-dc-images"
			data-product-id="<?php echo esc_attr( (string) $product_id ); ?>"
			data-default-image="<?php echo esc_url( $main ); ?>"
			data-combinations="<?php echo esc_attr( $combo_json ); ?>"
		>
			<div class="wpdude-dc-images__main">
				<?php if ( '' !== $main ) : ?>
					<img class="wpdude-dc-images__main-img" src="<?php echo esc_url( $main ); ?>" alt="" />
				<?php else : ?>
					<div class="wpdude-dc-images__placeholder"><?php echo esc_html__( 'No image', 'dude-commerce' ); ?></div>
				<?php endif; ?>
			</div>
			<?php if ( $show_thumbs ) : ?>
				<ul class="wpdude-dc-images__thumbs">
					<?php if ( '' !== $featured ) : ?>
						<li>
							<button type="button" class="wpdude-dc-images__thumb is-selected" data-full="<?php echo esc_url( $featured ); ?>" aria-current="true">
								<img src="<?php echo esc_url( get_the_post_thumbnail_url( $product_id, 'thumbnail' ) ?: $featured ); ?>" alt="" />
							</button>
						</li>
					<?php endif; ?>
					<?php foreach ( $gallery as $item ) : ?>
						<li>
							<button type="button" class="wpdude-dc-images__thumb<?php echo ( '' === $featured && $item['url'] === $main ) ? ' is-selected' : ''; ?>" data-full="<?php echo esc_url( $item['url'] ); ?>"<?php echo ( '' === $featured && $item['url'] === $main ) ? ' aria-current="true"' : ''; ?>>
								<img src="<?php echo esc_url( $item['thumb'] ); ?>" alt="" />
							</button>
						</li>
					<?php endforeach; ?>
					<?php foreach ( $combo_thumbs as $item ) : ?>
						<li>
							<button type="button" class="wpdude-dc-images__thumb wpdude-dc-images__thumb--combo" data-full="<?php echo esc_url( $item['url'] ); ?>" data-combo-key="<?php echo esc_attr( $item['key'] ); ?>">
								<img src="<?php echo esc_url( $item['thumb'] ); ?>" alt="" />
							</button>
						</li>
					<?php endforeach; ?>
				</ul>
			<?php endif; ?>
		</div>
		<?php
		return (string) ob_get_clean();
	}

	/**
	 * Render price markup.
	 */
	public static function render_price( int $product_id ): string {
		$type     = Product_Meta::get_type( $product_id );
		$currency = Product_Meta::get_currency( $product_id );
		$is_from  = Product_Meta::TYPE_OPTIONS === $type;
		$price    = self::default_price_formatted( $product_id );
		$map      = $is_from ? self::combination_map( $product_id ) : array();
		$json     = wp_json_encode( $map );
		if ( ! is_string( $json ) ) {
			$json = '{}';
		}
		$on_sale = $is_from
			? Product_Meta::has_combination_on_sale( $product_id )
			: Product_Meta::is_on_sale( $product_id );

		ob_start();
		?>
		<p
			class="wpdude-dc-price<?php echo $is_from ? ' wpdude-dc-price--from' : ''; ?>"
			data-product-id="<?php echo esc_attr( (string) $product_id ); ?>"
			data-currency="<?php echo esc_attr( $currency ); ?>"
			data-default-price="<?php echo esc_attr( $price ); ?>"
			data-price-mode="<?php echo esc_attr( $is_from ? 'from' : 'exact' ); ?>"
			data-any-on-sale="<?php echo $on_sale ? '1' : '0'; ?>"
			data-combinations="<?php echo esc_attr( $json ); ?>"
		>
			<span class="wpdude-dc-price__value"><?php echo esc_html( $price ); ?></span>
			<span class="wpdude-dc-price__sale"<?php echo $on_sale ? '' : ' hidden'; ?>><?php echo esc_html__( 'On sale', 'dude-commerce' ); ?></span>
		</p>
		<?php
		return (string) ob_get_clean();
	}
}
