import { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
import { __ } from '@wordpress/i18n';
import {
	Button,
	Card,
	CardBody,
	Flex,
	FlexItem,
	Icon,
} from '@wordpress/components';
import { check } from '@wordpress/icons';
import { Spinner } from '@woocommerce/components';
import { Quote } from '../../types/quote';
import { useWindowSize } from '../../shared/hooks';
import { Order } from '../../types/order';
import ordersToCheckoutValidatePayload from './utils/ordersToCheckoutValidatePayload';
import { PluginSettings } from 'types/settings';
import { useBulkQuotes } from './hooks/useBulkQuotes';
import { formatCurrency } from '../../shared/utils';

export default function BulkShipOverview({
	orders,
	onShipNow,
	defaultQuotes,
	settings,
}: {
	orders: Order[];
	onShipNow: () => void;
	defaultQuotes: Quote[];
	settings: PluginSettings;
}) {
  const {fetchBulkQuotes, loading: quotesLoading, error, quotes} = useBulkQuotes();
	const [isVisible, setIsVisible] = useState(false);
	const size = useWindowSize();
	const ordersPayload = ordersToCheckoutValidatePayload({ orders, settings });
	const Quotes = useMemo(() => quotes ?? defaultQuotes, [quotes, defaultQuotes]);
  
	const quoteRequests = useMemo(
		() =>
			ordersPayload.items.map((item) => ({
				ref: item.ref,
				origin: {
					country: item.origin.useAddress.country,
					postcode: item.origin.useAddress.postcode,
				},
				destination: {
					country: item.destination.useAddress.country,
					postcode: item.destination.useAddress.postcode,
				},
				serviceSlugs: item.serviceSlug ? [item.serviceSlug] : undefined,
				parcels: item.parcels.map((x) => ({
					ref: x.ref,
					weight: x.weight,
					height: x.height,
					length: x.length,
					width: x.width,
					value: x.value,
				})),
			})),
		// eslint-disable-next-line react-hooks/exhaustive-deps
		[orders, settings]
	);

	useEffect(() => {
		fetchBulkQuotes(quoteRequests);
	}, [quoteRequests, fetchBulkQuotes]);

	useEffect(() => {
		// Trigger animation on mount
		const timer = setTimeout(() => setIsVisible(true), 100);
		return () => clearTimeout(timer);
	}, []);

	const totalValue = useMemo(() => {
		const shipping =
			Quotes?.reduce((acc, quote) => acc + quote.price.gross, 0) ??
			0;
		const protection =
			Quotes?.reduce(
				(acc, quote) =>
					acc +
					(quote.availableExtras.find(
						(extra) => extra.key === 'protection:base'
					)?.price.gross ?? 0),
				0
			) ?? 0;
		return (shipping + protection) / 100;
	}, [Quotes]);

	const { displayPrice, isAnimating } = useAnimatedPrice(
		quotesLoading ? 0 : totalValue,
		800,
		quotesLoading
	);

	const orderLabel =
		orders.length === 1
			? __('1 order', 'parcel2go-shipping')
			: `${orders.length} ${__('orders', 'parcel2go-shipping')}`;

	const BulkShipContent = useMemo(
		(): ReactNode => (
			<Flex align="center" justify="center" gap={6} 
      style={{background: '#F0F0F1', padding: '8px 24px', borderRadius: 4}}>
				{!size.isXs && (
					<FlexItem>
						<Icon
							icon={check}
							size={24}
							style={{ fill: '#4ab866' }}
						/>
					</FlexItem>
				)}
				<FlexItem>
					{(!quotesLoading && !Quotes) ||
					Quotes?.length === 0 ? (
						<p
							style={{
								margin: 0,
								fontWeight: 600,
								fontSize: '1rem',
							}}
						>
							{__('Ship', 'parcel2go-shipping')} {orderLabel}
						</p>
					) : (
						<p
							style={{
								margin: 0,
								fontWeight: 600,
								fontSize: '1rem',
							}}
						>
							{__('Ship', 'parcel2go-shipping')} {orderLabel}{' '}
							{__('for', 'parcel2go-shipping')}
							{displayPrice === 0 && quotesLoading ? (
								<Spinner />
							) : (
								<span
									style={{
										color:
											isAnimating || quotesLoading
												? '#757575'
												: 'inherit',
										transition: 'color 0.3s',
									}}
								>
									{' '}{formatCurrency(displayPrice)}
								</span>
							)}{' '}
							<span style={{ fontWeight: 400, color: '#757575' }}>
								{__('inc VAT', 'parcel2go-shipping')}
							</span>
						</p>
					)}
				</FlexItem>

				<FlexItem>
					<Button
						variant="primary"
						onClick={onShipNow}
						disabled={orders.length === 0 || quotesLoading || !Quotes || Quotes.length === 0}
					>
						{__('Ship now', 'parcel2go-shipping')}
					</Button>
				</FlexItem>
			</Flex>
		),
		[
			displayPrice,
			isAnimating,
			onShipNow,
			orders.length,
			quotesLoading,
			Quotes,
			size.isXs,
			orderLabel,
		]
	);

	if (size.isXs) {
		// Mobile bottom banner with slide-in animation
		return (
			<div
				style={{
					position: 'fixed',
					bottom: 0,
					left: '50%',
					transform: `translateX(-50%) translateY(${isVisible ? '0' : '100px'})`,
					right: 0,
					padding: 16,
					width: '100%',
					transition:
						'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)',
					opacity: isVisible ? 1 : 0,
					zIndex: 1000,
				}}
			>
				<Card>
					<CardBody>{BulkShipContent}</CardBody>
				</Card>
			</div>
		);
	}

	return <div style={{ marginInline: '1rem' }}>{BulkShipContent}</div>;
}

// Custom hook for animated price counter
function useAnimatedPrice(
	targetPrice: number,
	duration: number = 800,
	isLoading: boolean = false
) {
	const [displayPrice, setDisplayPrice] = useState(targetPrice);
	const [isAnimating, setIsAnimating] = useState(false);
	const prevPriceRef = useRef(targetPrice);
	const animationRef = useRef<number>();

	useEffect(() => {
		// Don't animate if data is loading
		if (isLoading) {
			return;
		}

		if (prevPriceRef.current !== targetPrice && targetPrice > 0) {
			setIsAnimating(true);
			const startPrice = prevPriceRef.current;
			const priceDiff = targetPrice - startPrice;
			const startTime = Date.now();

			const animate = () => {
				const elapsed = Date.now() - startTime;
				const progress = Math.min(elapsed / duration, 1);

				// Easing function for smooth animation
				const easeProgress = 1 - Math.pow(1 - progress, 3);

				const currentPrice = startPrice + priceDiff * easeProgress;
				setDisplayPrice(currentPrice);

				if (progress < 1) {
					animationRef.current = requestAnimationFrame(animate);
				} else {
					setIsAnimating(false);
					setDisplayPrice(targetPrice);
					prevPriceRef.current = targetPrice;
				}
			};

			animationRef.current = requestAnimationFrame(animate);
		} else {
			prevPriceRef.current = targetPrice;
		}

		return () => {
			if (animationRef.current) {
				cancelAnimationFrame(animationRef.current);
			}
		};
	}, [targetPrice, duration, isLoading]);

	return { displayPrice, isAnimating };
}
