import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

import { Stars } from "@components/common/Icons";
import { MIcon } from "@components/common/MIcon";
import { ModalHeader } from "@components/common/ModalHeader";
import { SlideInPanel } from "@components/common/SlideInPanel";
import { Tooltip } from "@components/common/Tooltip";
import { useTemporaryRoutingMode } from "@hooks/useTemporaryRoutingMode";
import { toggleSettingsModal } from "@store/settingsSlice";
import type { ReduxStateType } from "@store/types";
import { LanguageSetting } from "./Language";
import { NotificationCheckbox } from "./Notifications";
import { RoutingModeSetting } from "./RoutingMode";
import { SettingsItem } from "./SettingsItem";
import { Slippage } from "./Slippage";
import { SmartBatching, SmartBatchingLabel } from "./SmartBatching";
import { SoundCheckbox } from "./Sound";

export const Settings = () => {
	const dispatch = useDispatch();
	function openModal() {
		dispatch(toggleSettingsModal(true));
	}

	const { dynamicSlippage, routingMode } = useSelector(
		(state: ReduxStateType) => state.settings,
	);
	const { isTemporarilySwitched, switchedToMode } = useTemporaryRoutingMode();

	const settingsChanged = !dynamicSlippage;

	const tooltipText = `Your routing temporarily changed to ${switchedToMode === "manual" ? "Manual" : "Auto"} for this swap.`;

	const infoIcon = isTemporarilySwitched ? (
		<Tooltip
			content={tooltipText}
			tooltipClassName="bn-min-w-[280px] bn-px-3"
			placement="top"
		>
			<MIcon name="info" classNames="bn-text-secondary bn-text-base" />
		</Tooltip>
	) : null;

	return (
		<button
			className="bn-relative bn-bg-transparent bn-flex bn-items-center bn-justify-center bn-cursor-pointer bn-text-primary bn-p-2 bn-rounded-full bn-border-[1.5px] bn-border-solid bn-text-sm bn-aeonik-font bn-h-8 hover:bn-border-accent-1 bn-border-subtle"
			onClick={openModal}
			type="button"
		>
			<span className="bn-mr-2 bn-leading-4 bn-font-medium">
				{routingMode === "auto" ? (
					<span className="bn-text-accent-1 bn-flex bn-items-center bn-space-x-1">
						{infoIcon}
						<Stars className="bn-text-base" fill="currentColor" />
						<span>Auto Mode</span>
					</span>
				) : (
					<span className="bn-flex bn-items-center bn-space-x-1">
						{infoIcon}
						<span>Manual Mode</span>
					</span>
				)}
			</span>
			<MIcon name="tune" classNames="bn-text-primary bn-text-base" />
			{settingsChanged ? <Indicator /> : null}
		</button>
	);
};

const Indicator = () => {
	return (
		<span className="bn-rounded-full bn-size-2 bn-absolute bn-top-1 bn-right-1 bn-flex bn-items-center bn-justify-center bn-bg-[#FF6631]/20">
			<span className="bn-size-1.5 bn-rounded-full bn-bg-[#FF6631]" />
		</span>
	);
};

export const SettingsModal = () => {
	const dispatch = useDispatch();
	const isModalOpen = useSelector(
		(state: ReduxStateType) => state.settings.isSettingsVisible,
	);
	const [homeHeight, setHomeHeight] = useState<number | null>(null);

	function closeModal() {
		dispatch(toggleSettingsModal(false));
	}

	// Measure Home component height when modal is open
	useEffect(() => {
		if (!isModalOpen) {
			setHomeHeight(null);
			return;
		}

		const homeElement = document.querySelector(
			"[data-home-component]",
		) as HTMLElement | null;

		if (!homeElement) {
			return;
		}

		let rafId: number | null = null;
		let lastHeight: number | null = null;
		let timeoutId: number | null = null;

		const updateHeight = () => {
			// Cancel any pending animation frame
			if (rafId !== null) {
				cancelAnimationFrame(rafId);
			}

			// Use requestAnimationFrame to batch updates and avoid excessive reflows
			rafId = requestAnimationFrame(() => {
				const height = homeElement.getBoundingClientRect().height;
				// Only update state if height actually changed (prevents unnecessary re-renders)
				if (lastHeight !== height) {
					lastHeight = height;
					setHomeHeight(height);
				}
			});
		};

		// Initial measurement
		updateHeight();

		// Use ResizeObserver to track height changes
		// Observe with border-box to catch all size changes including padding/border
		const resizeObserver = new ResizeObserver(() => {
			// ResizeObserver callback - only need to call updateHeight once
			// regardless of how many entries changed
			updateHeight();
		});

		// Observe the element - ResizeObserver automatically observes descendants
		// so we don't need to observe children separately
		resizeObserver.observe(homeElement, { box: "border-box" });

		// Fallback: Single check after 500ms to catch any initial missed changes
		// ResizeObserver handles subsequent changes, so we only need one delayed check
		timeoutId = setTimeout(() => {
			updateHeight();
		}, 500);

		return () => {
			if (rafId !== null) {
				cancelAnimationFrame(rafId);
			}
			if (timeoutId !== null) {
				clearTimeout(timeoutId);
			}
			resizeObserver.disconnect();
		};
	}, [isModalOpen]);

	const minHeight = Math.max(600, homeHeight || 600);

	return (
		<SlideInPanel
			isVisible={isModalOpen}
			closePanel={closeModal}
			trayClasses="bn-border-none"
			minHeight={minHeight}
			cardClasses="bn-h-full"
		>
			<ModalHeader
				closeModal={closeModal}
				label="Settings"
				subText="Customize and set preference on Bungee"
			/>
			<div className="bn-p-4">
				<div className="bn-mb-4">
					<RoutingModeSetting />
				</div>

				<Slippage />

				{settingsItems
					.filter((item) => item.featureEnabled)
					.map((item) => (
						<SettingsItem label={item.label} key={item.id}>
							{item.actionItem}
						</SettingsItem>
					))}
			</div>
		</SlideInPanel>
	);
};

// Excluded slippage
const settingsItems = [
	{
		id: "language",
		label: "Language",
		actionItem: <LanguageSetting />,
		featureEnabled: false,
	},
	{
		id: "sound",
		label: "Sound",
		actionItem: <SoundCheckbox />,
		featureEnabled: false,
	},
	{
		id: "notifications",
		label: "Notifications",
		actionItem: <NotificationCheckbox />,
		featureEnabled: false,
	},
	{
		id: "smart-batching",
		label: <SmartBatchingLabel />,
		actionItem: <SmartBatching />,
		featureEnabled: true,
	},
];
