"use client";

import { type ReactNode, useEffect } from "react";
import {
	BrowserRouter,
	MemoryRouter,
	Navigate,
	Outlet,
	Route,
	Routes,
	useLocation,
} from "react-router-dom";
import {
	OnboardingProvider,
	type OnboardingStepConfig,
	type OnboardingWizardConfig,
} from "./onboarding-context";

// =============================================================================
// UTILS
// =============================================================================

/**
 * Detect if we're running inside Next.js
 * Uses __NEXT_DATA__ which is set by Next.js on the window object
 */
function isNextJs(): boolean {
	if (typeof window === "undefined") return false;
	return "__NEXT_DATA__" in window;
}

/**
 * Get the initial path from the current browser URL, relative to basePath
 */
function getInitialPathFromUrl(basePath: string): string {
	if (typeof window === "undefined") return "/";

	const normalizedBase = basePath.endsWith("/")
		? basePath.slice(0, -1)
		: basePath;
	const currentPath = window.location.pathname;

	if (currentPath.startsWith(normalizedBase)) {
		const relativePath = currentPath.slice(normalizedBase.length);
		return relativePath || "/";
	}

	return "/";
}

// =============================================================================
// URL SYNC (for MemoryRouter in Next.js)
// =============================================================================

function UrlSync({ basePath }: { basePath: string }) {
	const location = useLocation();

	useEffect(() => {
		const normalizedBase = basePath.endsWith("/")
			? basePath.slice(0, -1)
			: basePath;
		const path = location.pathname === "/" ? "" : location.pathname;
		const fullPath = `${normalizedBase}${path}${location.search}${location.hash}`;

		if (
			window.location.pathname +
				window.location.search +
				window.location.hash !==
			fullPath
		) {
			window.history.replaceState(null, "", fullPath);
		}
	}, [location, basePath]);

	return null;
}

// =============================================================================
// ONBOARDING ROUTES
// =============================================================================

interface OnboardingRoutesProps {
	steps: OnboardingStepConfig[];
	layout?: React.ComponentType<{ children: ReactNode }>;
}

function OnboardingRoutes({ steps, layout: Layout }: OnboardingRoutesProps) {
	const firstStepPath = steps[0]?.path || "";

	// Wrapper to match dashboard pattern - Layout wraps an Outlet
	const LayoutWrapper = Layout
		? () => (
				<Layout>
					<Outlet />
				</Layout>
			)
		: undefined;

	return (
		<Routes>
			{LayoutWrapper ? (
				<Route element={<LayoutWrapper />}>
					{/* Redirect root to first step */}
					<Route index element={<Navigate to={firstStepPath} replace />} />

					{/* Step routes */}
					{steps.map((step) => {
						const StepComponent = step.component;
						return (
							<Route
								key={step.path}
								path={step.path}
								element={<StepComponent />}
							/>
						);
					})}

					{/* Fallback to first step */}
					<Route path="*" element={<Navigate to={firstStepPath} replace />} />
				</Route>
			) : (
				<>
					{/* Redirect root to first step */}
					<Route index element={<Navigate to={firstStepPath} replace />} />

					{/* Step routes */}
					{steps.map((step) => {
						const StepComponent = step.component;
						return (
							<Route
								key={step.path}
								path={step.path}
								element={<StepComponent />}
							/>
						);
					})}

					{/* Fallback to first step */}
					<Route path="*" element={<Navigate to={firstStepPath} replace />} />
				</>
			)}
		</Routes>
	);
}

// =============================================================================
// STEP COMPONENT WRAPPER
// =============================================================================

/**
 * HOC to inject onboarding props into step components
 * Use this when defining step components to receive navigation helpers
 */
export function withOnboardingStep<P extends object>(
	Component: React.ComponentType<P>,
): React.ComponentType<
	Omit<P, keyof import("./onboarding-context").OnboardingStepProps>
> {
	return function WrappedComponent(
		props: Omit<P, keyof import("./onboarding-context").OnboardingStepProps>,
	) {
		const { useOnboarding } = require("./onboarding-context");
		const onboardingProps = useOnboarding();
		return <Component {...(props as P)} {...onboardingProps} />;
	};
}

// =============================================================================
// ONBOARDING WIZARD
// =============================================================================

export interface OnboardingWizardProps extends OnboardingWizardConfig {
	/** Optional layout wrapper component */
	layout?: React.ComponentType<{ children: ReactNode }>;
}

/**
 * Self-contained onboarding wizard with routing
 *
 * Automatically detects environment:
 * - In Next.js: Uses MemoryRouter with URL sync to avoid conflicts
 * - In Vite/SPA: Uses BrowserRouter for native browser history
 *
 * @example
 * ```tsx
 * <OnboardingWizard
 *   basePath="/onboarding"
 *   steps={[
 *     { path: 'welcome', name: 'Welcome', component: WelcomeStep },
 *     { path: 'details', name: 'Details', component: DetailsStep },
 *     { path: 'complete', name: 'Complete', component: CompleteStep },
 *   ]}
 *   onComplete={() => navigate('/dashboard')}
 * />
 * ```
 */
export function OnboardingWizard({
	basePath = "/",
	steps,
	onComplete,
	onExit,
	layout,
}: OnboardingWizardProps) {
	const useMemoryRouter = isNextJs();
	const initialPath = getInitialPathFromUrl(basePath);

	const config: OnboardingWizardConfig = {
		basePath,
		steps,
		onComplete,
		onExit,
	};

	const content = (
		<OnboardingProvider config={config}>
			<OnboardingRoutes steps={steps} layout={layout} />
		</OnboardingProvider>
	);

	if (useMemoryRouter) {
		return (
			<MemoryRouter initialEntries={[initialPath]}>
				<UrlSync basePath={basePath} />
				{content}
			</MemoryRouter>
		);
	}

	return <BrowserRouter basename={basePath}>{content}</BrowserRouter>;
}
