/**
 * Default services form: displays shipping zone services, quote search, and selected couriers.
 */
import { __ } from '@wordpress/i18n';
import {
	memo,
	useEffect,
	useMemo,
	useState,
	useCallback,
} from '@wordpress/element';
import { Card, CardBody, Flex, Notice } from '@wordpress/components';
import { Spinner } from '@woocommerce/components';
import type {
	DefaultServiceMethod,
	DefaultServiceZone,
	Service,
} from '../../types';
import type {
	DefaultShippingSettings,
	PluginSettings,
	UpdateSettingsPayload,
	UpdateSettingsResponse,
} from '../../types/settings';
import type { PackagePreset } from '../../types/settings';
import { useQuotesFetcher } from '../../shared/hooks';
import { CourierSelectWithList } from '../../shared/components';
import { convertToAppSettings } from '../../shared/utils/parse';

type MethodRow = {
	zoneId: number;
	zoneName: string;
	countries: string[];
	countryCodes: string[];
	countryCount: number;
	method: DefaultServiceMethod;
};

function getQuoteCacheKey(methodId: string, row: MethodRow): string {
	const country = row.countryCodes?.[0]?.trim() ?? '';
	return `${methodId}:${country}`;
}

function pillStyle(background: string, color: string) {
	return {
		alignItems: 'center' as const,
		gap: 6,
		padding: '2px 8px',
		borderRadius: 12,
		background,
		color,
		fontSize: 12,
		lineHeight: 1.4,
	};
}

export interface DefaultServicesFormProps {
	zones: DefaultServiceZone[];
	loading?: boolean;
	error?: string | null;
	storeAddress?: DefaultShippingSettings | null;
	defaultPackage?: PackagePreset | null;
	/** From settings.overrides.defaultWeightKg (DefaultSettingsOverrides). No value = user must confirm before fetching when package has no weight. */
	defaultWeightKg?: number;
	settings: PluginSettings;
	handleSubmit: (
		payload: UpdateSettingsPayload
	) => Promise<UpdateSettingsResponse>;
}

function DefaultServicesFormInner({
	zones,
	loading = false,
	error = null,
	storeAddress = null,
	defaultPackage = null,
	defaultWeightKg,
	settings,
	handleSubmit,
}: DefaultServicesFormProps) {
	const rows = useMemo<MethodRow[]>(
		() =>
			zones.flatMap((zone) =>
				zone.methods.map((method) => ({
					zoneId: zone.id,
					zoneName: zone.name,
					countries: zone.countries,
					countryCodes: zone.countryCodes ?? [],
					countryCount: zone.countryCount,
					method,
				}))
			),
		[zones]
	);
	const [selectedCouriers, setSelectedCouriers] = useState<
		Record<string, Service[]>
	>({});
	const [savingMethodIds, setSavingMethodIds] = useState<
		Record<string, boolean>
	>({});
	const [saveFeedback, setSaveFeedback] = useState<
		Record<
			string,
			{ status: 'success' | 'error'; message: string } | undefined
		>
	>({});

	useEffect(() => {
		const next: Record<string, Service[]> = {};
		for (const row of rows) {
			if ( ! row.method.id ) continue;
			const saved = settings?.defaultServiceCouriers?.[ row.method.id ];
			next[ row.method.id ] = saved ?? row.method.services ?? [];
		}
		setSelectedCouriers(next);
	}, [rows, settings?.defaultServiceCouriers]);

	const effectiveWeight =
		defaultPackage && defaultPackage.weight > 0
			? defaultPackage.weight
			: typeof defaultWeightKg === 'number' && defaultWeightKg > 0
				? defaultWeightKg
				: 0;

	const hasWeightSet = effectiveWeight > 0;

	const origin = useMemo(
		() =>
			storeAddress
				? {
						country: storeAddress.country ?? '',
						countryName: storeAddress.country ?? '',
						postcode: storeAddress.postcode || undefined,
					}
				: {
						country: '',
						countryName: '',
						postcode: undefined as string | undefined,
					},
		[storeAddress]
	);

	const parcels = useMemo(
		() =>
			defaultPackage
				? [
						{
							ref: 'default-package',
							weight: effectiveWeight,
							length: defaultPackage.length,
							width: defaultPackage.width,
							height: defaultPackage.height,
							value: 100,
						},
					]
				: [],
		[defaultPackage, effectiveWeight]
	);

	const quotesFetcher = useQuotesFetcher({ origin, parcels });

	const canFetchQuotesForRow = useCallback(
		(row: MethodRow): boolean => {
			if (!storeAddress?.country?.trim()) return false;
			if (!defaultPackage) return false;
			if (
				defaultPackage.length < 1 ||
				defaultPackage.width < 1 ||
				defaultPackage.height < 1
			)
				return false;
			if (!hasWeightSet) return false;
			const firstCode = row.countryCodes?.[0]?.trim();
			if (!firstCode) return false;
			return true;
		},
		[storeAddress, defaultPackage, hasWeightSet]
	);

	const getQuoteMissingMessage = useCallback(
		(row: MethodRow): string | null => {
			if (!storeAddress?.country?.trim()) {
				return __(
					'Set your store address in Default shipping details to fetch quotes.',
					'parcel2go-shipping'
				);
			}
			if (!defaultPackage) {
				return __(
					'Choose or create a default package in Default package settings to fetch quotes.',
					'parcel2go-shipping'
				);
			}
			if (
				defaultPackage.length < 1 ||
				defaultPackage.width < 1 ||
				defaultPackage.height < 1
			) {
				return __(
					'Default package must have length, width and height set (Default package settings).',
					'parcel2go-shipping'
				);
			}
			if (!hasWeightSet) {
				return __(
					'Set default weight in Default settings overrides or add weight to your default package to fetch quotes.',
					'parcel2go-shipping'
				);
			}
			if (!row.countryCodes?.[0]?.trim()) {
				return __(
					'This zone has no country. Add at least one country to the shipping zone in WooCommerce to fetch quotes.',
					'parcel2go-shipping'
				);
			}
			return null;
		},
		[storeAddress, defaultPackage, hasWeightSet]
	);

	const applyServicesUpdate = useCallback(
		async (
			methodId: string,
			next: Service[],
			successMessage: string,
			errorMessage: string
		) => {
			const previous = selectedCouriers[methodId] ?? [];
			setSavingMethodIds((prev) => ({ ...prev, [methodId]: true }));
			setSaveFeedback((prev) => ({ ...prev, [methodId]: undefined }));
			setSelectedCouriers((prev) => ({ ...prev, [methodId]: next }));

			try {
				const appSettings = convertToAppSettings(settings);
				const payload: UpdateSettingsPayload = {
					type: 'App',
					data: {
						...appSettings,
						defaultServices: {
							...appSettings.defaultServices,
							[methodId]: next,
						},
					},
				};
				const result = await handleSubmit(payload);
				if (!result.success) {
					setSaveFeedback((prev) => ({
						...prev,
						[methodId]: {
							status: 'error',
							message: result.message || errorMessage,
						},
					}));
					
					setSelectedCouriers((prev) => ({
					...prev,
					[methodId]: previous,
				}));
				}

				setSaveFeedback((prev) => ({
					...prev,
					[methodId]: {
						status: 'success',
						message: result.message || successMessage,
					},
				}));
			} catch {
				setSelectedCouriers((prev) => ({
					...prev,
					[methodId]: previous,
				}));
				setSaveFeedback((prev) => ({
					...prev,
					[methodId]: { status: 'error', message: errorMessage },
				}));
			} finally {
				setSavingMethodIds((prev) => ({ ...prev, [methodId]: false }));
			}
		},
		[selectedCouriers, handleSubmit, settings]
	);

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

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

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

	if (loading) {
		return (
			<Flex justify="center" align="center" style={{ minHeight: 160 }}>
				<Spinner />
			</Flex>
		);
	}

	if (error) {
		return (
			<Notice status="error" isDismissible={false}>
				{error}
			</Notice>
		);
	}

	if (!rows.length) {
		return (
			<Notice status="warning" isDismissible={false}>
				{__('No shipping zones/services found.', 'parcel2go-shipping')}
			</Notice>
		);
	}

	return (
		<>
			<Card size="large">
				<CardBody
					style={{
						background: '#fff',
						boxShadow: '0 1px 3px rgba(0,0,0,0.06)',
					}}
				>
					<Flex direction="column" gap={0}>
						<div
							style={{
								padding: 16,
								borderBottom: '1px solid #ddd',
								fontWeight: 600,
							}}
						>
							{__('Default Services', 'parcel2go-shipping')}
						</div>
						{rows.map((row) => {
							const methodId = row.method.id;
							const chips = selectedCouriers[methodId] ?? [];
							const isSaving = savingMethodIds[methodId] === true;
							const feedback = saveFeedback[methodId] ?? null;
							const canFetch = canFetchQuotesForRow(row);
							const missingMessage = getQuoteMissingMessage(row);
							return (
								<div
									key={methodId}
									style={{ borderBottom: '1px solid #ddd' }}
								>
									<div
										style={{
											padding: '12px 16px',
											background: '#ececec',
										}}
									>
										<Flex
											justify="space-between"
											align="center"
										>
											<strong>{row.method.title}</strong>
											<span
												style={pillStyle(
													'#d7ebff',
													'#005a9c'
												)}
											>
												{row.method.price}
											</span>
										</Flex>
									</div>
									<div style={{ padding: 16 }}>
										{isSaving && (
											<Flex
												align="center"
												gap={2}
												style={{ marginBottom: 12 }}
											>
												<Spinner />
												<span>
													{__(
														'Saving default services…',
														'parcel2go-shipping'
													)}
												</span>
											</Flex>
										)}
										{feedback && (
											<Notice
												status={feedback.status}
												isDismissible={true}
												onRemove={() =>
													setSaveFeedback((prev) => ({
														...prev,
														[methodId]: undefined,
													}))
												}
											>
												{feedback.message}
											</Notice>
										)}
										<div
											style={{
												marginBottom: 10,
												color: '#646970',
											}}
										>
											<strong>
												{__(
													'Zone',
													'parcel2go-shipping'
												)}
												:
											</strong>{' '}
											{row.zoneName}
										</div>
										<div style={{ marginBottom: 12 }}>
											<strong>
												{__(
													'Countries',
													'parcel2go-shipping'
												)}
											</strong>
											<div style={{ marginTop: 6 }}>
												{row.countryCount}{' '}
												{row.countryCount === 1
													? __(
															'country',
															'parcel2go-shipping'
														)
													: __(
															'countries',
															'parcel2go-shipping'
														)}
											</div>
										</div>
										{row.method.conditions.length > 0 && (
											<div style={{ marginBottom: 12 }}>
												<strong>
													{__(
														'Conditions',
														'parcel2go-shipping'
													)}
												</strong>
												<div
													style={{
														marginTop: 6,
														display: 'flex',
														gap: 6,
														flexWrap: 'wrap',
													}}
												>
													{row.method.conditions.map(
														(condition) => (
															<span
																key={condition}
																style={pillStyle(
																	'#efefef',
																	'#1e1e1e'
																)}
															>
																{condition}
															</span>
														)
													)}
												</div>
											</div>
										)}
										<div>
											<strong>
												{__(
													'Couriers',
													'parcel2go-shipping'
												)}
											</strong>
											<CourierSelectWithList
												onOpenDropdown={() => {
													const key =
														getQuoteCacheKey(
															methodId,
															row
														);
													const dest = {
														country:
															row.countryCodes?.[0]?.trim() ??
															'',
													};
													quotesFetcher.setActiveCacheKey(
														key
													);
													quotesFetcher.fetchQuotes(
														key,
														dest
													);
												}}
												quotesList={
													quotesFetcher.quotesList
												}
												quotesLoading={
													quotesFetcher.quotesLoading
												}
												quotesError={
													quotesFetcher.quotesError
												}
												selectedCouriers={chips}
												onAddCourier={(service) =>
													addCourierFromQuote(
														methodId,
														service
													)
												}
												onRemoveCourier={(service) =>
													removeCourier(
														methodId,
														service
													)
												}
												disabled={isSaving}
												canFetch={canFetch}
												missingMessage={missingMessage}
												clearAllButton={{
													label: __(
														'Clear All',
														'parcel2go-shipping'
													),
													onClick: () =>
														clearAll(methodId),
													disabled: isSaving,
													isBusy: isSaving,
												}}
											/>
										</div>
									</div>
								</div>
							);
						})}
					</Flex>
				</CardBody>
			</Card>
		</>
	);
}

export const DefaultServicesForm = memo(DefaultServicesFormInner);
