import { forwardRef, useMemo, type ReactNode } from 'react';
import { View, type ViewProps } from 'react-native';
import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
import {
  cardContentVariants,
  cardFooterVariants,
  cardHeaderVariants,
  cardRootVariants,
  cardStripeVariants,
  type CardContentVariantProps,
  type CardFooterVariantProps,
  type CardVariantProps,
} from './styles';

// =============================================================================
// STYLED ROOT COMPONENT
// =============================================================================

const SCOPE = 'CARD';

const useCardStyleContext = () => useStyleContext(SCOPE) as CardVariantProps;

export interface CardProps extends ViewProps, CardVariantProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const CardRoot = forwardRef<View, CardProps>(
  ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
    const parent = useParentContext();
    const ctx = useMemo(() => ({ ...parent, [SCOPE]: { fullBleed } }), [parent, fullBleed]);

    const computedClassName = cn(cardRootVariants(), className);
    const Comp = asChild ? Slot : View;

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

CardRoot.displayName = 'Card';

// =============================================================================
// STYLED STRIPE COMPONENT
// =============================================================================

export interface CardStripeProps extends ViewProps {
  asChild?: boolean;
  className?: string;
}

const CardStripe = forwardRef<View, CardStripeProps>(
  ({ asChild, className, style, ...props }, ref) => {
    const computedClassName = cn(cardStripeVariants(), className);
    const Comp = asChild ? Slot : View;

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

CardStripe.displayName = 'Card.Stripe';

// =============================================================================
// STYLED HEADER COMPONENT
// =============================================================================

export interface CardHeaderProps extends ViewProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const CardHeader = forwardRef<View, CardHeaderProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const computedClassName = cn(cardHeaderVariants(), className);
    const Comp = asChild ? Slot : View;

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

CardHeader.displayName = 'Card.Header';

// =============================================================================
// STYLED CONTENT COMPONENT
// =============================================================================

export interface CardContentProps extends ViewProps, CardContentVariantProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const CardContent = forwardRef<View, CardContentProps>(
  ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
    const { fullBleed: fullBleedFromContext } = useCardStyleContext();
    const computedClassName = cn(
      cardContentVariants({ fullBleed: fullBleed ?? fullBleedFromContext }),
      className,
    );
    const Comp = asChild ? Slot : View;

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

CardContent.displayName = 'Card.Content';

// =============================================================================
// STYLED FOOTER COMPONENT
// =============================================================================

export interface CardFooterProps extends ViewProps, CardFooterVariantProps {
  asChild?: boolean;
  className?: string;
  children?: ReactNode;
}

const CardFooter = forwardRef<View, CardFooterProps>(
  ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
    const { fullBleed: fullBleedFromContext } = useCardStyleContext();
    const computedClassName = cn(
      cardFooterVariants({ fullBleed: fullBleed ?? fullBleedFromContext }),
      className,
    );
    const Comp = asChild ? Slot : View;

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

CardFooter.displayName = 'Card.Footer';

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

type CardCompoundComponent = typeof CardRoot & {
  Stripe: typeof CardStripe;
  Header: typeof CardHeader;
  Content: typeof CardContent;
  Footer: typeof CardFooter;
};

export const Card = Object.assign(CardRoot, {
  Stripe: CardStripe,
  Header: CardHeader,
  Content: CardContent,
  Footer: CardFooter,
}) as CardCompoundComponent;
