import { useCallback, useMemo, useState } from '@wordpress/element';
import { Button, CardBody, Flex, Modal, Notice } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { CourierSelectWithList } from '../../shared/components';
import type { Order } from '../../types/order';
import type { PluginSettings } from '../../types/settings';
import { useQuotesFetcher } from '../../shared/hooks';
import apiFetch from '@wordpress/api-fetch';
import type { QuotePayload, Service } from 'types/quote';
import { Spinner } from '@woocommerce/components';

interface SelectServiceModalProps {
	onClose: () => void;
	onRefreshOrders?: () => void;
	order: Order;
	settings: PluginSettings;
}

export default function SelectServiceModal({
	onClose,
	onRefreshOrders,
	order,
	settings,
}: SelectServiceModalProps) {
	const methodId = order.shipping_method?.id ?? null;
	const [selectedServices, setSelectedServices] = useState<Service[]>(
		methodId ? settings.defaultServiceCouriers[methodId] || [] : []
	);
	const [isSavingSelection, setIsSavingSelection] = useState(false);
	const [hasChanges, setHasChanges] = useState(false);
	const [saveFeedback, setSaveFeedback] = useState<{
		status: 'success' | 'error';
		message: string;
	} | null>(null);

	const defaultDimension = useMemo(() => {
		const defaultPackage = settings.packages.find(
			(p) => p.id === settings.defaultPackageId
		);
		return {
			weight:
				defaultPackage?.weight ||
				settings.overrides.defaultWeightKg ||
				1,
			length: defaultPackage?.length,
			width: defaultPackage?.width,
			height: defaultPackage?.height,
		};
	}, []);

	const origin: QuotePayload['origin'] = {
		country: settings.shipping?.country,
		countryName: settings.shipping?.countryName,
		postcode: settings.shipping?.postcode,
	};

	const destination: QuotePayload['destination'] = {
		country: order.shipping.country,
		countryName: order.shipping.country_name,
		postcode: order.shipping.postcode,
	};

	const parcels = order.items.map((item, index) => {
		const itemDimension = item.dimensions;
		const ref = item.product_id ?? `parcel-${index}`;
		const value = parseFloat(item.total) * 100;

		if (
			!itemDimension.width ||
			!itemDimension.length ||
			!itemDimension.height
		) {
			return {
				ref,
				weight: defaultDimension.weight,
				height: defaultDimension.height,
				length: defaultDimension.length,
				width: defaultDimension.width,
				value,
			};
		}

		return {
			ref,
			weight: Number(itemDimension.weight),
			height: Number(itemDimension.height),
			length: Number(itemDimension.length),
			width: Number(itemDimension.width),
			value,
		};
	});

	const quotesFetcher = useQuotesFetcher({ origin, destination, parcels });
	const missingMethodMessage = __(
		'This order has no shipping method/zone. Assign one in WooCommerce first, then set a default service.',
		'parcel2go-shipping'
	);

	const saveCouriers = useCallback(
		async (services: Service[]) => {
			if (!methodId) {
				setSaveFeedback({
					status: 'error',
					message: missingMethodMessage,
				});
				return;
			}
			await apiFetch({
				path: '/parcel2go-shipping/v1/settings/default-service-couriers',
				method: 'PATCH',
				data: { methodId, services },
			});
		},
		[methodId]
	);

	const applySelectedServices = useCallback(
		async (
			next: Service[],
			successMessage: string,
			errorMessage: string
		) => {
			const previous = selectedServices;
			setIsSavingSelection(true);
			setSaveFeedback(null);
			setSelectedServices(next);

			try {
				await saveCouriers(next);
				if (!methodId) {
					setSelectedServices(previous);
					return;
				}
				setSaveFeedback({ status: 'success', message: successMessage });
				setHasChanges(true);
			} catch {
				setSelectedServices(previous);
				setSaveFeedback({ status: 'error', message: errorMessage });
			} finally {
				setIsSavingSelection(false);
			}
		},
		[selectedServices, saveCouriers]
	);

	const addCourierFromQuote = useCallback(
		async (service: Service) => {
			if (selectedServices.some((s) => s.slug === service.slug)) return;
			const next = [...selectedServices, service];
			await applySelectedServices(
				next,
				__('Default service added successfully.', 'parcel2go-shipping'),
				__(
					'Failed to add default service. Please try again.',
					'parcel2go-shipping'
				)
			);
			quotesFetcher.setActiveCacheKey(null);
		},
		[selectedServices, applySelectedServices, quotesFetcher]
	);

	const removeCourier = useCallback(
		async (service: Service) => {
			const current = selectedServices ?? [];
			const next = current.filter((c) => c.slug !== service.slug);
			await applySelectedServices(
				next,
				__(
					'Default service removed successfully.',
					'parcel2go-shipping'
				),
				__(
					'Failed to remove default service. Please try again.',
					'parcel2go-shipping'
				)
			);
		},
		[selectedServices, applySelectedServices]
	);

	const clearAll = useCallback(async () => {
		await applySelectedServices(
			[],
			__('Default services cleared successfully.', 'parcel2go-shipping'),
			__(
				'Failed to clear default services. Please try again.',
				'parcel2go-shipping'
			)
		);
		quotesFetcher.setActiveCacheKey(null);
	}, [applySelectedServices, quotesFetcher]);

	const handleDropdownOpen = useCallback(() => {
		if (!methodId) {
			setSaveFeedback({ status: 'error', message: missingMethodMessage });
			return;
		}
		const key = `${methodId}-${order.shipping.country}`;
		quotesFetcher.setActiveCacheKey(key);
		quotesFetcher.fetchQuotes(key, destination);
	}, [order, destination, quotesFetcher]);

	const handleClose = useCallback(() => {
		if (hasChanges) {
			onRefreshOrders?.();
		}
		onClose();
	}, [hasChanges, onRefreshOrders, onClose, methodId]);

	const modalTitle = sprintf(
		__("Set a default service for '%s' ", 'parcel2go-shipping'),
		order.shipping_method?.title ||
			__('Unknown shipping method', 'parcel2go-shipping')
	);

	return (
		<Modal
			size="large"
			title={modalTitle}
			isDismissible={true}
			aria-describedby={__(
				'Default service selection',
				'parcel2go-shipping'
			)}
			shouldCloseOnClickOutside={false}
			onRequestClose={handleClose}
		>
			<CardBody style={{ background: '#f9f9f9' }}>
				<p>
					You can select multiple services to be automatically applied
					to new orders the cheapest that can handle the order will be
					selected.
				</p>
				<p>
					{sprintf(
						__('Quotes for order #%s', 'parcel2go-shipping'),
						order.id
					)}
				</p>
			</CardBody>
			{isSavingSelection && (
				<Flex align="center" gap={2} style={{ marginBottom: 12 }}>
					<Spinner />
					<span>
						{__('Saving default services…', 'parcel2go-shipping')}
					</span>
				</Flex>
			)}
			{saveFeedback && (
				<Notice
					status={saveFeedback.status}
					isDismissible={true}
					onRemove={() => setSaveFeedback(null)}
				>
					{saveFeedback.message}
				</Notice>
			)}
			<p style={{ marginBlock: 4 }}>Courier:</p>
			<CourierSelectWithList
				onOpenDropdown={handleDropdownOpen}
				quotesList={quotesFetcher.quotesList}
				quotesLoading={quotesFetcher.quotesLoading}
				quotesError={quotesFetcher.quotesError}
				selectedCouriers={selectedServices}
				onAddCourier={(service) => addCourierFromQuote(service)}
				onRemoveCourier={(service) => removeCourier(service)}
				canFetch={!isSavingSelection}
				missingMessage={null}
				clearAllButton={{
					label: __('Clear All', 'parcel2go-shipping'),
					onClick: clearAll,
					disabled: isSavingSelection,
					isBusy: isSavingSelection,
				}}
			/>
			<Flex justify="flex-end" gap={2} style={{ marginTop: 24 }}>
				<Button
					variant="secondary"
					onClick={handleClose}
					disabled={isSavingSelection}
				>
					{__('Close', 'parcel2go-shipping')}
				</Button>
			</Flex>
		</Modal>
	);
}
