import React, { forwardRef, useCallback, useContext, useRef, type ReactNode } from 'react';
import { Dimensions, View, ViewStyle } from 'react-native';
import { SafeAreaInsetsContext, type EdgeInsets } from 'react-native-safe-area-context';
import { useResolveClassNames } from 'uniwind';
import {
  BottomSheetModal,
  BottomSheetModalProvider,
  BottomSheetScrollView,
  BottomSheetView,
  BottomSheetBackdrop,
  BottomSheetFooter as GorhomBottomSheetFooter,
  type BottomSheetBackdropProps,
  type BottomSheetFooterProps as GorhomBottomSheetFooterProps,
  type BottomSheetModalProps as GorhomBottomSheetModalProps,
} from '@gorhom/bottom-sheet';
import { cn } from '@cdx-ui/utils';
import { ArrowBack, Close } from '@cdx-ui/icons';
import { Heading } from '../Heading';
import { IconButton } from '../IconButton';
import { Text } from '../Text';
import {
  bottomSheetBackgroundClassName,
  bottomSheetContentVariants,
  bottomSheetFooterVariants,
  bottomSheetHeaderVariants,
  bottomSheetModalContainerClassName,
} from './styles';

const ZERO_INSETS: EdgeInsets = { top: 0, bottom: 0, left: 0, right: 0 };

function useSafeInsets(): EdgeInsets {
  return useContext(SafeAreaInsetsContext) ?? ZERO_INSETS;
}

/** Ref type for BottomSheet; forwards the @gorhom modal ref (present, dismiss, snapToIndex, minimize, restore, etc.). */
export type BottomSheetModalRef = React.ComponentRef<typeof BottomSheetModal>;

export interface BottomSheetHeaderProps {
  title?: string;
  subtitle?: string;
  children?: ReactNode;
  className?: string;
  onClose?: () => void;
  closeAccessibilityLabel?: string;
  onBack?: () => void;
  backAccessibilityLabel?: string;
}

function BottomSheetHeaderComponent(
  {
    title,
    subtitle,
    children,
    className,
    onClose,
    closeAccessibilityLabel,
    onBack,
    backAccessibilityLabel = 'Go back',
  }: BottomSheetHeaderProps,
  ref: React.Ref<View>,
) {
  const hasTitle = title !== undefined && title !== '';
  const hasContent = hasTitle || !!children || !!onBack;
  const computedClassName = cn(bottomSheetHeaderVariants({ hasTitle: hasContent }), className);
  return (
    <View ref={ref} className={computedClassName}>
      <BottomSheetBackButton
        className={cn(!onBack && 'opacity-0')}
        onPress={onBack}
        {...(backAccessibilityLabel !== undefined && {
          accessibilityLabel: backAccessibilityLabel,
        })}
      />
      <View className="flex-1">
        {children ??
          (hasTitle ? (
            <View>
              <Heading size="sm" className="text-center">
                {title}
              </Heading>
              {subtitle ? (
                <Text size="sm" className="text-center text-content-secondary">
                  {subtitle}
                </Text>
              ) : null}
            </View>
          ) : null)}
      </View>
      <BottomSheetCloseButton
        className={cn(!onClose && 'opacity-0')}
        onPress={onClose}
        {...(closeAccessibilityLabel !== undefined && {
          accessibilityLabel: closeAccessibilityLabel,
        })}
      />
    </View>
  );
}

BottomSheetHeaderComponent.displayName = 'BottomSheet.Header';

const BottomSheetHeader = forwardRef<View, BottomSheetHeaderProps>(BottomSheetHeaderComponent);
BottomSheetHeader.displayName = 'BottomSheet.Header';

// =============================================================================
// BACKBUTTON
// =============================================================================
interface BottomSheetBackButtonProps {
  onPress?: () => void;
  className?: string;
  accessibilityLabel?: string;
}

function BottomSheetBackButton({
  onPress,
  className,
  accessibilityLabel = 'Go back',
}: Readonly<BottomSheetBackButtonProps>) {
  return (
    <IconButton
      as={ArrowBack}
      variant="solid"
      color="neutral"
      size="default"
      onPress={onPress}
      hitSlop={12}
      accessibilityLabel={accessibilityLabel}
      className={className}
    />
  );
}

BottomSheetBackButton.displayName = 'BottomSheet.BackButton';

// =============================================================================
// CLOSEBUTTON
// =============================================================================
interface BottomSheetCloseButtonProps {
  onPress?: () => void;
  className?: string;
  accessibilityLabel?: string;
}

function BottomSheetCloseButton({
  onPress,
  className,
  accessibilityLabel = 'Close',
}: Readonly<BottomSheetCloseButtonProps>) {
  return (
    <IconButton
      as={Close}
      variant="solid"
      color="neutral"
      size="default"
      onPress={onPress}
      hitSlop={12}
      accessibilityLabel={accessibilityLabel}
      className={className}
    />
  );
}

BottomSheetCloseButton.displayName = 'BottomSheet.CloseButton';

// =============================================================================
// CONTENT
// =============================================================================

export interface BottomSheetContentProps {
  children?: ReactNode;
  className?: string;
  hasSafeAreaInset?: boolean;
  style?: ViewStyle;
}

const BottomSheetContent = forwardRef<View, BottomSheetContentProps>(
  ({ children, className, hasSafeAreaInset, style }, ref) => {
    const insets = useSafeInsets();
    const computedClassName = cn(bottomSheetContentVariants(), className);
    return (
      <View
        ref={ref}
        className={computedClassName}
        style={hasSafeAreaInset ? { paddingBottom: insets.bottom, ...style } : style}
        pointerEvents="box-none"
      >
        {children}
      </View>
    );
  },
);

BottomSheetContent.displayName = 'BottomSheet.Content';

// =============================================================================
// FOOTER
// =============================================================================
export interface BottomSheetFooterProps {
  children?: ReactNode;
  className?: string;
  style?: ViewStyle;
}

const BottomSheetFooter = forwardRef<View, BottomSheetFooterProps>(
  ({ children, className, style }, ref) => {
    const insets = useSafeInsets();
    const computedClassName = cn(bottomSheetFooterVariants(), className);
    return (
      <View
        ref={ref}
        className={computedClassName}
        style={{ paddingBottom: Math.max(insets.bottom, 24), ...style }}
        pointerEvents="box-none"
      >
        {children}
      </View>
    );
  },
);

BottomSheetFooter.displayName = 'BottomSheet.Footer';

// =============================================================================
// MODAL WRAPPER (WITH STYLES)
// =============================================================================

export interface BottomSheetModalProps extends GorhomBottomSheetModalProps {
  /** Show the drag handle indicator. When false, `handleComponent` is set to null. @default true */
  handleVisible?: boolean;
  /** Footer content rendered via gorhom's BottomSheetFooter for proper animated positioning and safe-area handling. */
  footer?: ReactNode;
}

const MAX_DYNAMIC_CONTENT_SIZE = Dimensions.get('window').height * 0.9;

const CustomBackdrop = (props: BottomSheetBackdropProps) => {
  return (
    <BottomSheetBackdrop
      {...props}
      disappearsOnIndex={-1}
      appearsOnIndex={0}
      opacity={0.5}
      pressBehavior="close"
    />
  );
};

const CustomBackground = (props: React.ComponentPropsWithoutRef<typeof View>) => (
  <View {...props} className={bottomSheetBackgroundClassName} />
);

const BottomSheetModalStyled = forwardRef<
  React.ComponentRef<typeof BottomSheetModal>,
  BottomSheetModalProps
>(({ handleVisible = true, footer, onDismiss, onChange, ...rest }, ref) => {
  const renderFooter = useCallback(
    (props: GorhomBottomSheetFooterProps) => (
      <GorhomBottomSheetFooter {...props}>{footer}</GorhomBottomSheetFooter>
    ),
    [footer],
  );

  const dismissedRef = useRef(false);

  const handleDismiss = useCallback(() => {
    if (dismissedRef.current) return;
    dismissedRef.current = true;
    onDismiss?.();
  }, [onDismiss]);

  const handleChange = useCallback(
    (...args: Parameters<NonNullable<BottomSheetModalProps['onChange']>>) => {
      dismissedRef.current = false;
      onChange?.(...args);
    },
    [onChange],
  );

  const sheetContainerStyle = useResolveClassNames(bottomSheetModalContainerClassName);
  const handleIndicatorStyle = useResolveClassNames(
    'bg-surface-neutral-subtle w-9 h-[5px] rounded-full',
  );

  return (
    <BottomSheetModal
      ref={ref}
      enableDynamicSizing
      maxDynamicContentSize={MAX_DYNAMIC_CONTENT_SIZE}
      style={sheetContainerStyle}
      handleComponent={handleVisible ? undefined : null}
      handleIndicatorStyle={handleVisible ? handleIndicatorStyle : undefined}
      backdropComponent={CustomBackdrop}
      backgroundComponent={CustomBackground}
      {...rest}
      onDismiss={handleDismiss}
      onChange={handleChange}
      {...(footer != null && { footerComponent: renderFooter })}
    />
  );
});

BottomSheetModalStyled.displayName = 'BottomSheet.Modal';

// =============================================================================
// SCROLLVIEW WRAPPER (with footer margin adjustment enabled by default)
// =============================================================================

function BottomSheetScrollViewStyled({
  enableFooterMarginAdjustment = true,
  children,
  ...rest
}: React.ComponentPropsWithoutRef<typeof BottomSheetScrollView>) {
  return (
    <BottomSheetScrollView enableFooterMarginAdjustment={enableFooterMarginAdjustment} {...rest}>
      {children}
    </BottomSheetScrollView>
  );
}

BottomSheetScrollViewStyled.displayName = 'BottomSheet.ScrollView';

// =============================================================================
// VIEW WRAPPER (with footer margin adjustment enabled by default)
// =============================================================================

function BottomSheetViewStyled({
  enableFooterMarginAdjustment = true,
  children,
  ...rest
}: React.ComponentPropsWithoutRef<typeof BottomSheetView>) {
  return (
    <BottomSheetView enableFooterMarginAdjustment={enableFooterMarginAdjustment} {...rest}>
      {children}
    </BottomSheetView>
  );
}

BottomSheetViewStyled.displayName = 'BottomSheet.View';

// Display names for gorhom components exposed as BottomSheet.*
interface WithDisplayName {
  displayName?: string;
}
(BottomSheetModalProvider as WithDisplayName).displayName = 'BottomSheet.Provider';

// ── Public exports ────────────────────────────────────────

interface BottomSheetCompound {
  Modal: typeof BottomSheetModalStyled;
  Header: typeof BottomSheetHeader;
  Content: typeof BottomSheetContent;
  Footer: typeof BottomSheetFooter;
  Provider: typeof BottomSheetModalProvider;
  ScrollView: typeof BottomSheetScrollViewStyled;
  View: typeof BottomSheetViewStyled;
}

export const BottomSheet = {
  Modal: BottomSheetModalStyled,
  Header: BottomSheetHeader,
  Content: BottomSheetContent,
  Footer: BottomSheetFooter,
  Provider: BottomSheetModalProvider,
  ScrollView: BottomSheetScrollViewStyled,
  View: BottomSheetViewStyled,
} as BottomSheetCompound;

// ── Hooks ────────────────────────────────────────────────

export function useBottomSheet() {
  const ref = useRef<BottomSheetModalRef>(null);
  return { ref, present: () => ref.current?.present(), dismiss: () => ref.current?.dismiss() };
}
