import { isEmpty } from 'lodash';
import {
	useCallback,
	useMemo,
	useState,
	useEffect,
	useRef,
} from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { labelPurchaseStore } from 'data/label-purchase';
import {
	getAccountSettings,
	getAvailableCarrierPackages,
	getAvailablePackagesById,
	getPackageDimensions,
	getWeightUnit,
	convertWeightToUnit,
	WEIGHT_UNITS,
} from 'utils';
import {
	CustomPackage,
	Package,
	ShipmentItem,
	ReturnShipmentInfo,
} from 'types';
import { defaultCustomPackageData } from '../constants';
import {
	CUSTOM_BOX_ID_PREFIX,
	CUSTOM_PACKAGE_TYPES,
	TAB_NAMES,
} from '../packages';

export const getInitialPackageAndTab = (
	savedPackages: Package[]
): {
	initialTab: string;
	initialPackage: Package | null;
} => {
	const isUseLastBoxEnabled =
		getAccountSettings()?.purchaseSettings?.use_last_package;
	const lastBoxId = getAccountSettings()?.userMeta?.last_box_id;

	if ( isUseLastBoxEnabled && lastBoxId ) {
		const matchingSavedPackage = savedPackages.find(
			( { id } ) => id === lastBoxId
		);

		if ( matchingSavedPackage ) {
			return {
				initialTab: TAB_NAMES.SAVED_TEMPLATES,
				initialPackage: {
					...matchingSavedPackage,
					...( getPackageDimensions( matchingSavedPackage ) || {} ),
				},
			};
		}

		if ( getAvailableCarrierPackages() ) {
			const allCarrierPackagesById = getAvailablePackagesById();
			if ( Object.keys( allCarrierPackagesById ).includes( lastBoxId ) ) {
				return {
					initialTab: TAB_NAMES.CARRIER_PACKAGE,
					initialPackage: {
						...allCarrierPackagesById[ lastBoxId ],
						...( getPackageDimensions(
							allCarrierPackagesById[ lastBoxId ]
						) || {} ),
					},
				};
			}
		}
	}

	return {
		initialTab: TAB_NAMES.CUSTOM_PACKAGE,
		initialPackage: null,
	};
};

export function usePackageState(
	currentShipmentId: string,
	shipments: Record< string, ShipmentItem[] >,
	totalWeight: number,
	returnShipments?: Record< string, ReturnShipmentInfo >,
	setShipmentTotalWeight?: ( weight: number ) => void
) {
	const savedPackages = useSelect(
		( select ) => select( labelPurchaseStore ).getSavedPackages(),
		// eslint-disable-next-line react-hooks/exhaustive-deps -- we want this to update when the shipmentId changes
		[ currentShipmentId ]
	);
	const { initialTab, initialPackage } = useMemo(
		() => getInitialPackageAndTab( savedPackages ),
		[ savedPackages ]
	);
	const [ initialCarrierTab, setInitialCarrierTab ] = useState< string >();

	// Initialize tab state only once, and don't reset it when initialTab changes
	const [ currentPackageTab, setCurrentPackageTabState ] = useState(
		() => initialTab
	);

	// Prevent initialTab changes from overriding our restoration
	const previousInitialTab = useRef( initialTab );
	useEffect( () => {
		// Only update tab from initialTab if this is the very first time or if we're not in a return shipment
		if ( previousInitialTab.current !== initialTab ) {
			// Check if this is a return shipment - if so, don't override with initialTab
			const returnShipment = returnShipments?.[ currentShipmentId ];
			if ( ! returnShipment?.isReturn ) {
				setCurrentPackageTabState( initialTab );
			}

			previousInitialTab.current = initialTab;
		}
	}, [ initialTab, currentShipmentId, returnShipments, currentPackageTab ] );

	// Wrap setCurrentPackageTab for consistent interface
	const setCurrentPackageTab = useCallback( ( tab: string ) => {
		setCurrentPackageTabState( tab );
	}, [] );
	const [ customPackageData, setCustomPackageData ] = useState<
		Record< string, CustomPackage >
	>( {
		[ currentShipmentId ]: defaultCustomPackageData,
	} );
	const initialPackages = Object.keys( shipments ).reduce(
		( packages: Record< string, Package | null >, id: string ) => {
			packages[ id ] = initialPackage;
			return packages;
		},
		{}
	);
	const [ selectedPackage, setSelected ] =
		useState< Record< string, Package | CustomPackage | null > >(
			initialPackages
		);

	const setCustomPackage = useCallback(
		( data: CustomPackage ) => {
			setCustomPackageData( ( prev ) => ( {
				...( prev || {} ),
				[ currentShipmentId ]: data,
			} ) );
		},
		[ currentShipmentId ]
	);

	const hasDistinctDimensions = (
		pkg: CustomPackage | Package
	): pkg is CustomPackage =>
		Object.hasOwn( pkg, 'length' ) &&
		Object.hasOwn( pkg, 'width' ) &&
		Object.hasOwn( pkg, 'height' );

	const setSelectedPackage = useCallback(
		( pkg: Package | CustomPackage ) => {
			setSelected( ( prev ) => ( {
				...( prev || {} ),
				[ currentShipmentId ]: {
					...pkg,
					...( hasDistinctDimensions( pkg )
						? pkg
						: getPackageDimensions( pkg ) || {} ),
				},
			} ) );
		},
		[ currentShipmentId ]
	);

	const getCustomPackage = useCallback( () => {
		if ( customPackageData[ currentShipmentId ] ) {
			return {
				...customPackageData[ currentShipmentId ],
				isLetter:
					customPackageData[ currentShipmentId ].type ===
					CUSTOM_PACKAGE_TYPES.ENVELOPE,
			};
		}
		return defaultCustomPackageData;
	}, [ currentShipmentId, customPackageData ] );

	const getSelectedPackage = useCallback( () => {
		let shipmentPackage = selectedPackage[ currentShipmentId ];
		if ( ! shipmentPackage ) {
			shipmentPackage = initialPackage;
		}
		return shipmentPackage;
	}, [ selectedPackage, currentShipmentId, initialPackage ] );

	const isCustomPackageTab = useCallback(
		() => currentPackageTab === TAB_NAMES.CUSTOM_PACKAGE,
		[ currentPackageTab ]
	);
	const getPackageForRequest = useCallback(
		() =>
			isCustomPackageTab()
				? getCustomPackage()
				: ( getSelectedPackage() as Package ),
		[ getCustomPackage, getSelectedPackage, isCustomPackageTab ]
	);

	const isSelectedASavedPackage = useCallback( () => {
		return savedPackages.some( ( p ) => p.id === getSelectedPackage()?.id );
	}, [ savedPackages, getSelectedPackage ] );

	const isPackageSpecified = () => {
		if ( totalWeight === 0 ) return false;

		if ( currentPackageTab === TAB_NAMES.CUSTOM_PACKAGE ) {
			const { width, height, length } = getCustomPackage();
			return [ width, height, length ]
				.map( parseFloat )
				.every( ( dimension ) => dimension > 0 );
		}
		if ( currentPackageTab === TAB_NAMES.CARRIER_PACKAGE ) {
			return (
				! isEmpty( getSelectedPackage() ) &&
				! getSelectedPackage()?.id.includes( CUSTOM_BOX_ID_PREFIX )
			);
		}

		// currentPackageTab === TAB_NAMES.SAVED_TEMPLATES
		return ! isEmpty( getSelectedPackage() ) && isSelectedASavedPackage();
	};

	/**
	 * Helper function to create a custom package from preserved label data
	 */
	const createCustomPackageFromLabel = useCallback(
		( preservedPackage: ReturnShipmentInfo[ 'preservedPackage' ] ) => {
			if ( ! preservedPackage ) return null;

			// Convert package weight from stored unit (oz) to store's configured unit
			let boxWeight = preservedPackage.packageWeight ?? 0;
			if ( boxWeight > 0 ) {
				const storedUnit =
					( preservedPackage.packageWeightUnit as
						| ( typeof WEIGHT_UNITS )[ keyof typeof WEIGHT_UNITS ]
						| undefined ) ?? 'oz';
				const storeUnit = getWeightUnit();
				boxWeight = convertWeightToUnit(
					boxWeight,
					storedUnit,
					storeUnit
				);
			}

			return {
				length: String( preservedPackage.packageLength ?? '' ),
				width: String( preservedPackage.packageWidth ?? '' ),
				height: String( preservedPackage.packageHeight ?? '' ),
				boxWeight,
				id: CUSTOM_BOX_ID_PREFIX,
				type: CUSTOM_PACKAGE_TYPES.BOX,
				dimensions: `${ preservedPackage.packageLength ?? 0 } x ${
					preservedPackage.packageWidth ?? 0
				} x ${ preservedPackage.packageHeight ?? 0 }`,
				isUserDefined: true,
				name: 'Return Package (from original)',
			} as CustomPackage;
		},
		[]
	);

	/**
	 * Helper function to check if preserved package has label data
	 */
	const hasLabelPackageData = useCallback(
		( preservedPackage: ReturnShipmentInfo[ 'preservedPackage' ] ) => {
			if ( ! preservedPackage ) return false;
			return (
				preservedPackage.packageWeight !== undefined ||
				preservedPackage.packageLength !== undefined ||
				preservedPackage.packageWidth !== undefined ||
				preservedPackage.packageHeight !== undefined
			);
		},
		[]
	);

	/**
	 * Effect to restore package data from label information
	 */
	useEffect( () => {
		if ( ! returnShipments ) {
			return;
		}

		const returnShipment = returnShipments[ currentShipmentId ];
		const { preservedPackage } = returnShipment || {};

		// Only proceed if this is a return shipment with preserved package data
		if ( ! returnShipment?.isReturn || ! preservedPackage ) {
			return;
		}

		if ( hasLabelPackageData( preservedPackage ) ) {
			// Check if this is a saved template first
			if ( preservedPackage.packageName && savedPackages.length > 0 ) {
				const matchingSavedPackage = savedPackages.find(
					( pkg ) => pkg.name === preservedPackage.packageName
				);

				if ( matchingSavedPackage ) {
					// Use the saved template
					setCurrentPackageTab( TAB_NAMES.SAVED_TEMPLATES );
					setSelectedPackage( matchingSavedPackage );

					// Simulate a tab click to update the TabPanel UI
					setTimeout( () => {
						const tabsContainer =
							document.querySelector( '.package-tabs' );
						if ( tabsContainer ) {
							const tabButton = tabsContainer.querySelector(
								`button[id$="${ TAB_NAMES.SAVED_TEMPLATES }"]`
							);
							if (
								tabButton &&
								tabButton instanceof HTMLButtonElement
							) {
								tabButton.click();
							}
						}
					}, 100 );

					// Set total weight if available
					if (
						preservedPackage.packageWeight !== undefined &&
						setShipmentTotalWeight
					) {
						setShipmentTotalWeight(
							preservedPackage.packageWeight
						);
					}
					return;
				}
			}

			// Check if this might be a carrier package using packageId
			if ( preservedPackage.packageId ) {
				const allCarrierPackagesById = getAvailablePackagesById();

				// Try both string and number versions for compatibility
				const carrierPackage =
					allCarrierPackagesById[ preservedPackage.packageId ];
				const carrierPackageStr =
					allCarrierPackagesById[
						String( preservedPackage.packageId )
					];
				const carrierPackageNum =
					allCarrierPackagesById[
						Number( preservedPackage.packageId )
					];

				const finalCarrierPackage =
					carrierPackage || carrierPackageStr || carrierPackageNum;

				if ( finalCarrierPackage ) {
					// Find which carrier this package belongs to
					const carrierPackages = getAvailableCarrierPackages();
					let foundCarrierId: string | undefined;
					for ( const [ carrierId, groups ] of Object.entries(
						carrierPackages
					) ) {
						for ( const group of Object.values(
							groups as Record< string, unknown >
						) ) {
							const typedGroup = group as {
								definitions?: { id: string | number }[];
							};
							if (
								typedGroup.definitions?.some(
									( pkg ) =>
										pkg.id === preservedPackage.packageId
								)
							) {
								foundCarrierId = carrierId;
								break;
							}
						}
						if ( foundCarrierId ) break;
					}

					// Switch to carrier package tab
					setCurrentPackageTab( TAB_NAMES.CARRIER_PACKAGE );
					setSelectedPackage( finalCarrierPackage );

					// Set the initial carrier tab so the correct carrier is selected
					if ( foundCarrierId ) {
						setInitialCarrierTab( foundCarrierId );
					}

					// Simulate tab click for carrier packages
					setTimeout( () => {
						const tabsContainer =
							document.querySelector( '.package-tabs' );
						if ( tabsContainer ) {
							const tabButton = tabsContainer.querySelector(
								`button[id$="${ TAB_NAMES.CARRIER_PACKAGE }"]`
							);
							if (
								tabButton &&
								tabButton instanceof HTMLButtonElement
							) {
								tabButton.click();

								// After the main tab is clicked, we need to click the carrier sub-tab
								setTimeout( () => {
									const carrierTabsContainer =
										document.querySelector(
											'.carrier-package-tabs'
										);
									if (
										carrierTabsContainer &&
										foundCarrierId
									) {
										const carrierTabButton =
											carrierTabsContainer.querySelector(
												`button[id$="${ foundCarrierId }"]`
											);
										if (
											carrierTabButton &&
											carrierTabButton instanceof
												HTMLButtonElement
										) {
											carrierTabButton.click();
										}
									}
								}, 100 );
							}
						}
					}, 100 );

					// Set total weight if available
					if (
						preservedPackage.packageWeight !== undefined &&
						setShipmentTotalWeight
					) {
						setShipmentTotalWeight(
							preservedPackage.packageWeight
						);
					}
					return;
				}
				// Fallback: search by package name if packageId doesn't work
				if ( preservedPackage.packageName ) {
					const carrierPackages = getAvailableCarrierPackages();
					let foundPackage:
						| { id: string | number; name: string }
						| undefined;
					let foundCarrierId: string | undefined;

					searchLoop: for ( const [
						carrierId,
						groups,
					] of Object.entries( carrierPackages ) ) {
						for ( const group of Object.values(
							groups as Record< string, unknown >
						) ) {
							const typedGroup = group as {
								definitions?: {
									id: string | number;
									name: string;
								}[];
							};
							if ( typedGroup.definitions ) {
								foundPackage = typedGroup.definitions.find(
									( pkg ) =>
										pkg.name ===
										preservedPackage.packageName
								);
								if ( foundPackage ) {
									foundCarrierId = carrierId;
									break searchLoop;
								}
							}
						}
					}

					if ( foundPackage && foundCarrierId ) {
						// Switch to carrier package tab
						setCurrentPackageTab( TAB_NAMES.CARRIER_PACKAGE );
						setSelectedPackage( foundPackage as Package );
						setInitialCarrierTab( foundCarrierId );

						// Simulate tab click for carrier packages
						setTimeout( () => {
							const tabsContainer =
								document.querySelector( '.package-tabs' );
							if ( tabsContainer ) {
								const tabButton = tabsContainer.querySelector(
									`button[id$="${ TAB_NAMES.CARRIER_PACKAGE }"]`
								);
								if (
									tabButton &&
									tabButton instanceof HTMLButtonElement
								) {
									tabButton.click();

									// After the main tab is clicked, we need to click the carrier sub-tab
									setTimeout( () => {
										const carrierTabsContainer =
											document.querySelector(
												'.carrier-package-tabs'
											);
										if (
											carrierTabsContainer &&
											foundCarrierId
										) {
											const carrierTabButton =
												carrierTabsContainer.querySelector(
													`button[id$="${ foundCarrierId }"]`
												);
											if (
												carrierTabButton &&
												carrierTabButton instanceof
													HTMLButtonElement
											) {
												carrierTabButton.click();
											}
										}
									}, 100 );
								}
							}
						}, 100 );

						// Set total weight if available
						if (
							preservedPackage.packageWeight !== undefined &&
							setShipmentTotalWeight
						) {
							setShipmentTotalWeight(
								preservedPackage.packageWeight
							);
						}
						return;
					}
				}
			}

			// Otherwise create a custom package from the preserved label data
			setCurrentPackageTab( TAB_NAMES.CUSTOM_PACKAGE );

			const customPackageFromLabel =
				createCustomPackageFromLabel( preservedPackage );
			if ( customPackageFromLabel ) {
				setCustomPackage( customPackageFromLabel );
			}

			// Note: TotalWeight component will calculate and set the total weight
			// by adding item weights + boxWeight (which is now correctly converted)
		}
	}, [
		currentShipmentId,
		returnShipments,
		createCustomPackageFromLabel,
		hasLabelPackageData,
		setCustomPackage,
		setCurrentPackageTab,
		setShipmentTotalWeight,
		savedPackages,
		setSelectedPackage,
		setInitialCarrierTab,
	] );

	/**
	 * Effect to restore legacy package selection data
	 */
	useEffect( () => {
		if ( ! returnShipments ) {
			return;
		}

		const returnShipment = returnShipments[ currentShipmentId ];
		const { preservedPackage } = returnShipment || {};

		// Only proceed for return shipments with legacy package data
		if (
			! returnShipment?.isReturn ||
			! preservedPackage ||
			hasLabelPackageData( preservedPackage )
		) {
			return;
		}

		try {
			// Restore total weight if available
			if (
				preservedPackage.totalWeight !== undefined &&
				setShipmentTotalWeight
			) {
				setShipmentTotalWeight( preservedPackage.totalWeight );
			}

			// Restore package tab selection and data
			if ( preservedPackage.isCustomPackageTab ) {
				// Switch to custom package tab and restore custom package data
				setCurrentPackageTab( TAB_NAMES.CUSTOM_PACKAGE );

				if ( preservedPackage.customPackage ) {
					setCustomPackage(
						preservedPackage.customPackage as CustomPackage
					);
				}
			} else {
				// Switch to carrier package tab and restore selected package
				setCurrentPackageTab( TAB_NAMES.CARRIER_PACKAGE );

				if ( preservedPackage.selectedPackage ) {
					setSelectedPackage(
						preservedPackage.selectedPackage as Package
					);
				}
			}
		} catch {
			// Handle package restoration errors gracefully
		}
	}, [
		currentShipmentId,
		returnShipments,
		hasLabelPackageData,
		setCustomPackage,
		setSelectedPackage,
		setCurrentPackageTab,
		setShipmentTotalWeight,
	] );

	return {
		getCustomPackage,
		setCustomPackage,
		getSelectedPackage,
		setSelectedPackage,
		currentPackageTab,
		setCurrentPackageTab,
		getPackageForRequest,
		isPackageSpecified,
		isSelectedASavedPackage,
		isCustomPackageTab,
		initialCarrierTab,
		setInitialCarrierTab,
	};
}
