import { forwardRef, useEffect, type ReactNode } from 'react';
import { Text, type TextProps, View, type ViewProps } from 'react-native';
import { ErrorIcon } from '@cdx-ui/icons';
import {
  FieldLabel as FieldLabelPrimitive,
  FieldRoot as FieldRootPrimitive,
  Slot,
  dataAttributes,
  mergeDataAttributes,
  useFormControlContext,
  type FieldLabelProps as FieldLabelPrimitiveProps,
  type FieldRootProps as FieldRootPrimitiveProps,
} from '@cdx-ui/primitives';
import { cn } from '@cdx-ui/utils';
import { Icon } from '../Icon';
import {
  fieldErrorIconVariants,
  fieldErrorTextVariants,
  fieldErrorVariants,
  fieldHelperTextVariants,
  fieldHelperVariants,
  fieldLabelVariants,
  fieldRootVariants,
  type FieldErrorVariantProps,
  type FieldHelperVariantProps,
  type FieldLabelVariantProps,
  type FieldRootVariantProps,
} from './styles';

// =============================================================================
// FIELD ROOT
// =============================================================================

/**
 * Field wrapper + context. For **initial focus**, pass `autoFocus` on `Input.Field` (not here).
 */
export interface FieldRootProps extends FieldRootPrimitiveProps, FieldRootVariantProps {}

const FieldRoot = forwardRef<View, FieldRootProps>(
  ({ className, children, style, ...props }, ref) => {
    const computedClassName = cn(fieldRootVariants(), className);

    return (
      <FieldRootPrimitive
        ref={ref}
        className={computedClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'field' }))}
      >
        {children}
      </FieldRootPrimitive>
    );
  },
);

FieldRoot.displayName = 'Field';

// =============================================================================
// FIELD LABEL
// =============================================================================

export interface FieldLabelProps extends FieldLabelPrimitiveProps, FieldLabelVariantProps {}

const FieldLabel = forwardRef<View, FieldLabelProps>(
  ({ className, children, style, htmlFor, ...props }, ref) => {
    const { isLabelFocused, isInvalid } = useFormControlContext();
    // Native: inject text-content-action via context (group-has CSS handles web).
    // native: prefix keeps this class inert on web so it never conflicts with text-content-primary.
    const labelClassName = cn(
      fieldLabelVariants(),
      isLabelFocused && !isInvalid && 'native:text-content-action',
      className,
    );

    return (
      <FieldLabelPrimitive
        ref={ref}
        className={labelClassName}
        style={style}
        htmlFor={htmlFor}
        requiredIndicator={
          <Text className="text-content-danger" aria-hidden>
            {' *'}
          </Text>
        }
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'field-label' }))}
      >
        {children}
      </FieldLabelPrimitive>
    );
  },
);

FieldLabel.displayName = 'Field.Label';

// =============================================================================
// FIELD HELPER (styled-only — reads form context directly)
// =============================================================================

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

const FieldHelper = forwardRef<View, FieldHelperProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const { helpTextId, setHasHelpText, isInvalid } = useFormControlContext();

    useEffect(() => {
      if (isInvalid) {
        setHasHelpText?.(false);
        return undefined;
      }
      setHasHelpText?.(true);
      return () => {
        setHasHelpText?.(false);
      };
    }, [setHasHelpText, isInvalid]);

    if (isInvalid) {
      return null;
    }

    const containerClassName = cn(fieldHelperVariants(), className);
    const textClassName = cn(fieldHelperTextVariants());
    const Comp = asChild ? Slot : View;

    return (
      <Comp
        ref={ref}
        className={containerClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'field-helper' }))}
      >
        <Text id={helpTextId} className={textClassName}>
          {children}
        </Text>
      </Comp>
    );
  },
);

FieldHelper.displayName = 'Field.Helper';

// =============================================================================
// FIELD ERROR (styled-only — reads form context directly)
// =============================================================================

const FieldErrorIcon = ({
  className,
  style,
  ...props
}: {
  className?: string;
  style?: TextProps['style'];
}) => {
  const computedClassName = cn(fieldErrorIconVariants(), className);

  return (
    <Icon
      as={ErrorIcon}
      className={computedClassName}
      style={style}
      aria-hidden={true}
      {...props}
      {...mergeDataAttributes(props, dataAttributes({ slot: 'field-error-icon' }))}
    />
  );
};

FieldErrorIcon.displayName = 'Field.ErrorIcon';

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

const FieldError = forwardRef<View, FieldErrorProps>(
  ({ asChild, className, children, style, ...props }, ref) => {
    const { isInvalid, feedbackId, setHasFeedbackText } = useFormControlContext();

    const visible = Boolean(isInvalid && children);

    useEffect(() => {
      if (!visible) {
        setHasFeedbackText?.(false);
        return undefined;
      }
      setHasFeedbackText?.(true);
      return () => {
        setHasFeedbackText?.(false);
      };
    }, [setHasFeedbackText, visible]);

    if (!visible) {
      return null;
    }

    const containerClassName = cn(fieldErrorVariants(), className);
    const textClassName = cn(fieldErrorTextVariants());
    const Comp = asChild ? Slot : View;

    return (
      <Comp
        ref={ref}
        id={feedbackId}
        accessibilityRole="alert"
        accessibilityLiveRegion="assertive"
        className={containerClassName}
        style={style}
        {...props}
        {...mergeDataAttributes(props, dataAttributes({ slot: 'field-error' }))}
      >
        <FieldErrorIcon />
        <Text className={textClassName}>{children}</Text>
      </Comp>
    );
  },
);

FieldError.displayName = 'Field.Error';

// =============================================================================
// COMPOUND EXPORT
// =============================================================================

type FieldCompoundComponent = typeof FieldRoot & {
  Label: typeof FieldLabel;
  Helper: typeof FieldHelper;
  Error: typeof FieldError;
};

export const Field = Object.assign(FieldRoot, {
  Label: FieldLabel,
  Helper: FieldHelper,
  Error: FieldError,
}) as FieldCompoundComponent;
