import { createContext, useContext, type ReactNode, type ComponentType } from 'react'
import type { NavigationProvider, LinkProps, NavigateOptions } from '../types'

export interface NavigationContextValue {
  /** Navigate to a path */
  navigate: (to: string, options?: NavigateOptions) => void
  /** Get current path */
  getCurrentPath: () => string
  /** Link component for rendering navigation links */
  Link: ComponentType<LinkProps>
}

export const NavigationContext = createContext<NavigationContextValue | null>(null)

/** Default link component using plain anchor tags */
function DefaultLink({ href, children, className }: LinkProps) {
  return (
    <a href={href} className={className}>
      {children}
    </a>
  )
}

/** Default navigation using window.location */
const defaultNavigationProvider: NavigationProvider = {
  navigate: (to, options) => {
    if (options?.replace) {
      window.history.replaceState(options.state, '', to)
    } else {
      window.location.href = to
    }
  },
  getCurrentPath: () => window.location.pathname,
  LinkComponent: DefaultLink,
}

export interface NavigationProviderProps {
  children: ReactNode
  navigationProvider?: NavigationProvider
}

/**
 * Provides navigation capabilities to child components.
 * Allows integration with different routers (react-router, next/router, etc.)
 *
 * @example
 * ```tsx
 * // With react-router
 * import { Link, useNavigate, useLocation } from 'react-router-dom'
 *
 * const reactRouterProvider: NavigationProvider = {
 *   navigate: (to, options) => navigate(to, options),
 *   getCurrentPath: () => location.pathname,
 *   LinkComponent: ({ href, children, className }) => (
 *     <Link to={href} className={className}>{children}</Link>
 *   ),
 * }
 *
 * <NavigationProvider navigationProvider={reactRouterProvider}>
 *   <App />
 * </NavigationProvider>
 * ```
 */
export function NavigationProvider({
  children,
  navigationProvider = defaultNavigationProvider,
}: NavigationProviderProps) {
  return (
    <NavigationContext.Provider
      value={{
        navigate: navigationProvider.navigate,
        getCurrentPath: navigationProvider.getCurrentPath,
        Link: navigationProvider.LinkComponent,
      }}
    >
      {children}
    </NavigationContext.Provider>
  )
}

/**
 * Hook to access navigation capabilities.
 * Must be used within a NavigationProvider.
 *
 * @example
 * ```tsx
 * const { navigate, getCurrentPath, Link } = useNavigation()
 *
 * // Programmatic navigation
 * navigate('/dashboard')
 *
 * // Link rendering
 * <Link href="/settings">Settings</Link>
 * ```
 */
export function useNavigation(): NavigationContextValue {
  const context = useContext(NavigationContext)
  if (!context) {
    throw new Error('useNavigation must be used within a NavigationProvider')
  }
  return context
}
