import { forwardRef, useEffect, useMemo, type ReactNode } from 'react';
import { Image, Text, View, type ImageProps, type TextProps, type ViewProps } from 'react-native';
import {
  AvatarRoot as AvatarRootPrimitive,
  Slot,
  dataAttributes,
  mergeDataAttributes,
  useAvatarContext,
  type IAvatarImageProps,
  type IAvatarProps,
} from '@cdx-ui/primitives';
import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
import { Icon as IconComponent, type IconProps } from '../Icon';
import {
  type AvatarVariantProps,
  avatarBadgeVariants,
  avatarIconVariants,
  avatarTextVariants,
  avatarImageVariants,
  avatarRootVariants,
} from './styles';

const SCOPE = 'AVATAR';

const useAvatarStyleContext = () => useStyleContext(SCOPE) as AvatarVariantProps;

// =============================================================================
// UTILITIES
// =============================================================================

function getInitials(name: string): string {
  const trimmed = name.trim();
  const words = trimmed.split(/\s+/);

  if (words.length === 1 && trimmed.length <= 2) {
    return trimmed.toUpperCase();
  }

  let result = '';
  for (const word of words) {
    if (word.length > 0) {
      result += word.charAt(0);
    }
    if (result.length >= 2) break;
  }
  return result.toUpperCase();
}

// =============================================================================
// AVATAR ROOT
// =============================================================================

export interface AvatarProps extends ViewProps, IAvatarProps, AvatarVariantProps {
  className?: string;
  children?: ReactNode;
}

const AvatarRoot = forwardRef<View, AvatarProps>(
  ({ size = 'md', className, children, style, ...props }, ref) => {
    const computedClassName = cn(avatarRootVariants({ size }), className);

    const parent = useParentContext();
    const ctx = useMemo(() => ({ ...parent, [SCOPE]: { size } }), [parent, size]);

    return (
      <ParentContext.Provider value={ctx}>
        <AvatarRootPrimitive
          ref={ref}
          className={computedClassName}
          style={style}
          {...props}
          {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar' }))}
        >
          {children}
        </AvatarRootPrimitive>
      </ParentContext.Provider>
    );
  },
);

AvatarRoot.displayName = 'Avatar';

// =============================================================================
// AVATAR IMAGE
// =============================================================================

export interface AvatarImageProps extends Omit<ImageProps, 'source'>, IAvatarImageProps {
  asChild?: boolean;
  className?: string;
}

const AvatarImage = forwardRef<Image, AvatarImageProps>(
  ({ asChild, className, style, src, source, onLoad, onError, ...props }, ref) => {
    const { imageError, setImageLoaded, setImageError } = useAvatarContext();
    const computedClassName = cn(avatarImageVariants(), className);

    const resolvedSource = useMemo(() => (src ? { uri: src } : source), [src, source]);

    useEffect(() => {
      if (!resolvedSource) {
        setImageError(true);
      } else {
        setImageError(false);
        setImageLoaded(false);
      }
    }, [resolvedSource, setImageError, setImageLoaded]);

    if (!resolvedSource || imageError) {
      return null;
    }

    const Comp = asChild ? Slot : Image;

    return (
      <Comp
        ref={ref}
        source={resolvedSource}
        className={computedClassName}
        style={style}
        onLoad={(e: unknown) => {
          setImageLoaded(true);
          if (onLoad) (onLoad as (e: unknown) => void)(e);
        }}
        onError={(e: unknown) => {
          setImageError(true);
          if (onError) (onError as (e: unknown) => void)(e);
        }}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar-image' }))}
      />
    );
  },
);

AvatarImage.displayName = 'Avatar.Image';

// =============================================================================
// AVATAR TEXT
// =============================================================================

export interface AvatarTextProps extends TextProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const AvatarText = forwardRef<Text, AvatarTextProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const { size } = useAvatarStyleContext();
    const { imageLoaded, imageError } = useAvatarContext();
    const visible = !imageLoaded || imageError;
    const computedClassName = cn(avatarTextVariants({ size }), className);

    const text = typeof children === 'string' ? getInitials(children) : children;

    const Comp = asChild ? Slot : Text;

    return (
      <Comp
        ref={ref}
        className={computedClassName}
        style={[style, !visible && { opacity: 0 }]}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar-text' }))}
      >
        {text}
      </Comp>
    );
  },
);

AvatarText.displayName = 'Avatar.Text';

// =============================================================================
// AVATAR ICON
// =============================================================================

export interface AvatarIconProps extends Omit<IconProps, 'children'> {
  asChild?: boolean;
  className?: string;
}

const AvatarIcon = ({ asChild, className, style, ...props }: AvatarIconProps) => {
  const { size } = useAvatarStyleContext();
  const { imageLoaded, imageError } = useAvatarContext();
  const visible = !imageLoaded || imageError;
  const computedClassName = cn(avatarIconVariants({ size }), className);

  if (asChild) {
    return (
      <Slot
        className={computedClassName}
        style={[style, !visible && { opacity: 0 }]}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar-icon' }))}
      />
    );
  }

  return (
    <IconComponent
      className={computedClassName}
      style={[style, !visible && { opacity: 0 }]}
      {...props}
      {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar-icon' }))}
    />
  );
};

AvatarIcon.displayName = 'Avatar.Icon';

// =============================================================================
// AVATAR BADGE
// =============================================================================

/**
 * @deprecated Use the generic `Badge` component instead.
 * Wrap your `Avatar` in `<Badge placement="bottom-end" overlap="circular">` for equivalent behavior.
 */
export interface AvatarBadgeProps extends ViewProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

/**
 * @deprecated Use the generic `Badge` component instead.
 * Wrap your `Avatar` in `<Badge placement="bottom-end" overlap="circular">` for equivalent behavior.
 */
const AvatarBadge = forwardRef<View, AvatarBadgeProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const { size } = useAvatarStyleContext();
    const computedClassName = cn(avatarBadgeVariants({ size }), className);
    const Comp = asChild ? Slot : View;

    return (
      <Comp
        ref={ref}
        className={computedClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'avatar-badge' }))}
      >
        {children}
      </Comp>
    );
  },
);

AvatarBadge.displayName = 'Avatar.Badge';

// =============================================================================
// COMPOUND COMPONENT
// =============================================================================

type AvatarCompoundComponent = typeof AvatarRoot & {
  Image: typeof AvatarImage;
  Text: typeof AvatarText;
  Icon: typeof AvatarIcon;
  Badge: typeof AvatarBadge;
};

export const Avatar = Object.assign(AvatarRoot, {
  Image: AvatarImage,
  Text: AvatarText,
  Icon: AvatarIcon,
  Badge: AvatarBadge,
}) as AvatarCompoundComponent;

export type { AvatarVariantProps };
