import { Spinner } from '@woocommerce/components';
import { Card, CardBody, Flex, Modal, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { lazy, Suspense, useCallback, useMemo, useState } from 'react';
import {
	BookingModalFooter,
	CheckoutErrorNotice,
	OrderCompleteView,
	OrderProgress,
	PaymentModal,
	PrepayTopUp,
} from '../../shared/components';
import type { Order, OrderItemDimensions } from '../../types/order';
import type { PluginSettings } from '../../types/settings';
import type {
	CheckoutApiError,
	GenericPaymentResponse,
	PrepayAPI,
	PrePayBalance,
} from '../../types';
import { useBulkShipFlow } from './hooks/useBulkShipFlow';
import { PrepayProcessing } from './PrepayProcessing';

const LazyBulkShipOverview = lazy(() => import('./bulk-ship-overview'));
const LazyBulkShipBreakdown = lazy(() => import('./bulk-ship-breakdown'));

interface BulkShipProps {
	selectedOrders: Order[];
	onComplete: () => void;
	settings: PluginSettings;
	prepayBalance: PrePayBalance;
	isBalanceLoading: boolean;
	prepayError: string | null;
	fetchBalance: () => void;
	makePrepayPayment: (
		orderId: string,
		hash: string
	) => Promise<GenericPaymentResponse>;
	createTopUp: PrepayAPI['createTopUp'];
	isLinked: boolean;
}

export default function BulkShip({
	selectedOrders,
	onComplete,
	settings,
	prepayBalance,
	isBalanceLoading,
	prepayError,
	fetchBalance,
	makePrepayPayment,
	createTopUp,
	isLinked,
}: BulkShipProps) {
	const flow = useBulkShipFlow(selectedOrders, settings, onComplete);

	const orderIds = useMemo(
		() => [...new Set((selectedOrders ?? []).map((o) => o.id))],
		[selectedOrders]
	);

	const defaultPackage = useMemo(
		() =>
			settings?.packages?.find(
				(p) => p.id === settings.defaultPackageId
			) as OrderItemDimensions | undefined,
		[settings]
	);

	const amount = (flow.validationResult?.price?.gross ?? 0) / 100;
	const balance = prepayBalance?.balance;

	const handlePayByCard = useCallback(async () => {
		await flow.handlePayment('card', makePrepayPayment);
	}, [flow, makePrepayPayment]);

	const handlePayByPrepay = useCallback(async () => {
		await flow.handlePayment('prepay', makePrepayPayment);
	}, [flow, makePrepayPayment]);

	const modalTitle = useMemo(() => {
		const isSuccessStep = flow.step === 'success';
		if (flow.isValidating || !flow.validationResult)
			return __('Validating orders...', 'parcel2go-shipping');
		if (flow.isCreatingOrder)
			return __('Creating order...', 'parcel2go-shipping');
		if (flow.inProgress)
			return __('Order in progress...', 'parcel2go-shipping');
		if (isSuccessStep || flow.isFulfilled)
			return __('Order fulfilled', 'parcel2go-shipping');
		return `${__('Bulk ship', 'parcel2go-shipping')} ${orderIds.length} ${__('orders', 'parcel2go-shipping')}`;
	}, [
		flow.step,
		flow.isValidating,
		flow.validationResult,
		flow.isCreatingOrder,
		flow.inProgress,
		flow.isFulfilled,
		orderIds.length,
	]);

	return (
		<>
			{orderIds.length > 0 && (
				<Suspense fallback={<Spinner />}>
					<LazyBulkShipOverview
						orders={selectedOrders}
						onShipNow={flow.validateOrder}
						defaultQuotes={selectedOrders
							.filter((o) => o.cheapestQuote)
							.map((o) => o.cheapestQuote!)}
						settings={settings}
					/>
				</Suspense>
			)}

			{(flow.step === 'confirming' || flow.step === 'success') && (
				<Modal
					size="large"
					title={modalTitle}
					isDismissible
					shouldCloseOnClickOutside={false}
					aria-describedby={__(
						'Bulk ship orders',
						'parcel2go-shipping'
					)}
					onRequestClose={flow.handleClose}
				>
					<ModalContent
						flow={flow}
						selectedOrders={selectedOrders}
						defaultPackage={defaultPackage}
						settings={settings}
						isBalanceLoading={isBalanceLoading}
					/>

					{flow.step === 'confirming' && (
						<div style={{ marginTop: 24, paddingTop: 16 }}>
						<BookingModalFooter
							amount={amount}
							balance={balance}
							fulfilled={flow.isFulfilled}
							working={flow.working}
							isLoading={flow.isValidating || flow.inProgress}
							hasError={
								!!flow.validationResult?.error || !!flow.error
							}
							isLinked={isLinked}
							onClose={flow.handleClose}
							onPayWithPrePay={handlePayByPrepay}
							onPayWithProviders={handlePayByCard}
							setPrePayTopup={() => flow.setStep('prepay-topup')}
							onComplete={onComplete}
						/>
						</div>
					)}
				</Modal>
			)}

			{flow.step === 'prepay-processing' && (
				<PrepayProcessing onRequestClose={flow.handleClose} />
			)}

			{flow.step === 'payment' && flow.pendingPayment && (
				<PaymentModal
					paymentOrder={flow.pendingPayment}
					onRequestClose={flow.handleClose}
					onPaymentSuccess={(response) =>
						flow.onPaymentSuccess(response, flow.pendingPayment!)
					}
				/>
			)}

			{flow.step === 'prepay-topup' && (
				<PrepayTopUp
					prepayBalance={prepayBalance}
					createTopUp={createTopUp}
					loading={isBalanceLoading}
					error={prepayError}
					onTopUpSuccess={() => {
						void fetchBalance();
						flow.setStep('confirming');
					}}
					Wrapper={({ children }) => (
						<Modal
							size="large"
							title={__(
								'Top up PrePay balance',
								'parcel2go-shipping'
							)}
							isDismissible
							shouldCloseOnClickOutside={false}
							onRequestClose={() => flow.setStep('confirming')}
						>
							<Card style={{ background: '#f6f7f7' }}>
								<CardBody>{children}</CardBody>
							</Card>
						</Modal>
					)}
				/>
			)}
		</>
	);
}

// ── Modal content — isolated so it doesn't re-render the whole modal ──
function ModalContent({
	flow,
	selectedOrders,
	defaultPackage,
	settings,
	isBalanceLoading,
}) {
	if (flow.isValidating || !flow.validationResult || flow.isCreatingOrder) {
		return (
			<Flex justify="center" align="center" style={{ minHeight: 200 }}>
				<Spinner />
			</Flex>
		);
	}

	if (flow.inProgress) {
		return (
			<Suspense fallback={<Spinner />}>
				<OrderProgress
					paid={flow.progress.paid}
					booked={flow.progress.booked}
					fulfilled={flow.progress.fulfilled}
					attempts={flow.progress.attempts}
					orderReference={
						flow.poller.totalOrders > 1
							? `(${flow.poller.totalOrders} ${__('orders', 'parcel2go-shipping')})`
							: flow.orderReference?.reference
					}
					orderLineCount={flow.progress.orderLineCount}
					bookedOrderLineCount={flow.progress.bookedOrderLineCount}
				/>
			</Suspense>
		);
	}

	if (flow.isFulfilled) {
		const baseOrder = selectedOrders[0];
		const completeOrder = {
			...baseOrder,
			p2g: {
				...(baseOrder?.p2g ?? {}),
				orderId:
					flow.p2gOrderId || baseOrder?.p2g?.orderId || '',
				orderLineIds:
					flow.p2gOrderLineIds.length > 0
						? flow.p2gOrderLineIds
						: (baseOrder?.p2g?.orderLineIds ?? []),
			},
		};

		return (
			<Suspense fallback={<Spinner />}>
				<OrderCompleteView
					isFulfilled={flow.isFulfilled}
					order={completeOrder}
					onBack={flow.handleClose}
					orderLabel={`Order ${selectedOrders[0].id}`}
					p2gOrderLineIds={flow.p2gOrderLineIds}
					labelHashSavedThisSession={flow.labelHashSavedThisSession}
				/>
			</Suspense>
		);
	}

	return (
		<>
			{!isBalanceLoading &&
				flow.validationResult &&
				!flow.validationResult.error && (
					<Suspense fallback={<Spinner />}>
						<LazyBulkShipBreakdown
							validationResult={flow.validationResult}
							orders={selectedOrders}
							defaultPackage={defaultPackage}
							settings={settings}
						/>
					</Suspense>
				)}

			{flow.error && (
				<Notice
					status="error"
					isDismissible
					onRemove={() => flow.setError(null)}
				>
					{flow.error}
				</Notice>
			)}

			{flow.validationResult?.error && (
					<CheckoutErrorNotice
						error={flow.validationResult.error as unknown as CheckoutApiError}
					/>
			)}
		</>
	);
}
