/**
 * External dependencies
 */
import classnames from 'classnames';
import { sprintf, _n } from '@wordpress/i18n';
import Label from '@woocommerce/base-components/label';
import ProductPrice from '@woocommerce/base-components/product-price';
import ProductName from '@woocommerce/base-components/product-name';
import {
	getCurrencyFromPriceResponse,
	formatPrice,
} from '@woocommerce/price-format';
import {
	__experimentalApplyCheckoutFilter,
	mustContain,
} from '@woocommerce/blocks-checkout';
import Dinero from 'dinero.js';
import { getSetting } from '@woocommerce/settings';
import { useMemo } from '@wordpress/element';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import { CartItem, isString } from '@woocommerce/types';

/**
 * Internal dependencies
 */
import ProductBackorderBadge from '../product-backorder-badge';
import ProductImage from '../product-image';
import ProductLowStockBadge from '../product-low-stock-badge';
import ProductMetadata from '../product-metadata';

const productPriceValidation = ( value: string ): true | never =>
	mustContain( value, '<price/>' );

interface OrderSummaryProps {
	cartItem: CartItem;
}

const OrderSummaryItem = ( { cartItem }: OrderSummaryProps ): JSX.Element => {
	const {
		images,
		low_stock_remaining: lowStockRemaining,
		show_backorder_badge: showBackorderBadge,
		name: initialName,
		permalink,
		prices,
		quantity,
		short_description: shortDescription,
		description: fullDescription,
		item_data: itemData,
		variation,
		totals,
		extensions,
	} = cartItem;

	// Prepare props to pass to the __experimentalApplyCheckoutFilter filter.
	// We need to pluck out receiveCart.
	// eslint-disable-next-line no-unused-vars
	const { receiveCart, ...cart } = useStoreCart();

	const arg = useMemo(
		() => ( {
			context: 'summary',
			cartItem,
			cart,
		} ),
		[ cartItem, cart ]
	);

	const priceCurrency = getCurrencyFromPriceResponse( prices );

	const name = __experimentalApplyCheckoutFilter( {
		filterName: 'itemName',
		defaultValue: initialName,
		extensions,
		arg,
	} );

	const regularPriceSingle = Dinero( {
		amount: parseInt( prices.raw_prices.regular_price, 10 ),
		precision: isString( prices.raw_prices.precision )
			? parseInt( prices.raw_prices.precision, 10 )
			: prices.raw_prices.precision,
	} )
		.convertPrecision( priceCurrency.minorUnit )
		.getAmount();
	const priceSingle = Dinero( {
		amount: parseInt( prices.raw_prices.price, 10 ),
		precision: isString( prices.raw_prices.precision )
			? parseInt( prices.raw_prices.precision, 10 )
			: prices.raw_prices.precision,
	} )
		.convertPrecision( priceCurrency.minorUnit )
		.getAmount();
	const totalsCurrency = getCurrencyFromPriceResponse( totals );

	let lineSubtotal = parseInt( totals.line_subtotal, 10 );
	if ( getSetting( 'displayCartPricesIncludingTax', false ) ) {
		lineSubtotal += parseInt( totals.line_subtotal_tax, 10 );
	}
	const subtotalPrice = Dinero( {
		amount: lineSubtotal,
		precision: totalsCurrency.minorUnit,
	} ).getAmount();
	const subtotalPriceFormat = __experimentalApplyCheckoutFilter( {
		filterName: 'subtotalPriceFormat',
		defaultValue: '<price/>',
		extensions,
		arg,
		validation: productPriceValidation,
	} );

	// Allow extensions to filter how the price is displayed. Ie: prepending or appending some values.
	const productPriceFormat = __experimentalApplyCheckoutFilter( {
		filterName: 'cartItemPrice',
		defaultValue: '<price/>',
		extensions,
		arg,
		validation: productPriceValidation,
	} );

	const cartItemClassNameFilter = __experimentalApplyCheckoutFilter( {
		filterName: 'cartItemClass',
		defaultValue: '',
		extensions,
		arg,
	} );

	return (
		<div
			className={ classnames(
				'wc-block-components-order-summary-item',
				cartItemClassNameFilter
			) }
		>
			<div className="wc-block-components-order-summary-item__image">
				<div className="wc-block-components-order-summary-item__quantity">
					<Label
						label={ quantity.toString() }
						screenReaderLabel={ sprintf(
							/* translators: %d number of products of the same type in the cart */
							_n(
								'%d item',
								'%d items',
								quantity,
								'woo-gutenberg-products-block'
							),
							quantity
						) }
					/>
				</div>
				<ProductImage
					image={ images.length ? images[ 0 ] : {} }
					fallbackAlt={ name }
				/>
			</div>
			<div className="wc-block-components-order-summary-item__description">
				<ProductName
					disabled={ true }
					name={ name }
					permalink={ permalink }
				/>
				<ProductPrice
					currency={ priceCurrency }
					price={ priceSingle }
					regularPrice={ regularPriceSingle }
					className="wc-block-components-order-summary-item__individual-prices"
					priceClassName="wc-block-components-order-summary-item__individual-price"
					regularPriceClassName="wc-block-components-order-summary-item__regular-individual-price"
					format={ subtotalPriceFormat }
				/>
				{ showBackorderBadge ? (
					<ProductBackorderBadge />
				) : (
					!! lowStockRemaining && (
						<ProductLowStockBadge
							lowStockRemaining={ lowStockRemaining }
						/>
					)
				) }
				<ProductMetadata
					shortDescription={ shortDescription }
					fullDescription={ fullDescription }
					itemData={ itemData }
					variation={ variation }
				/>
			</div>
			<span className="screen-reader-text">
				{ sprintf(
					/* translators: %1$d is the number of items, %2$s is the item name and %3$s is the total price including the currency symbol. */
					_n(
						'Total price for %1$d %2$s item: %3$s',
						'Total price for %1$d %2$s items: %3$s',
						quantity,
						'woo-gutenberg-products-block'
					),
					quantity,
					name,
					formatPrice( subtotalPrice, totalsCurrency )
				) }
			</span>
			<div
				className="wc-block-components-order-summary-item__total-price"
				aria-hidden="true"
			>
				<ProductPrice
					currency={ totalsCurrency }
					format={ productPriceFormat }
					price={ subtotalPrice }
				/>
			</div>
		</div>
	);
};

export default OrderSummaryItem;
