import { clsx } from '@trail-ui/shared-utils';
import { ForwardedRef, ReactElement, ReactNode, cloneElement, forwardRef } from 'react';
import type { SwitchProps as AriaSwitchProps } from 'react-aria-components';
import { Switch as AriaSwitch } from 'react-aria-components';
import { CheckIcon, CloseIcon } from '@trail-ui/icons';

export type SwitchIconProps = {
  width: string;
  height: string;
  isSelected: boolean;
  className: string;
};

export interface SwitchProps extends AriaSwitchProps {
  icon?: ReactNode | ((props: SwitchIconProps) => ReactNode);
  className?: string;
  size?: 'sm' | 'md' | 'lg';
  label: string;
  onValueChange?: (value: boolean, props: SwitchIconProps) => void;
}

function Switch(props: SwitchProps, ref: ForwardedRef<HTMLLabelElement>) {
  const { children, className, size = 'sm', label, icon, onValueChange, ...otherProps } = props;

  // Base styles
  const baseStyles = clsx(
    'inline-flex items-center gap-2 cursor-pointer transition-all duration-200',
    'data-[disabled=true]:opacity-50 data-[disabled=true]:pointer-events-none',
    className,
  );

  // Size configurations
  const sizeConfig = {
    sm: {
      wrapper: 'w-9 h-5',
      thumb: 'w-4 h-4',
      thumbOnPosition: 'translate-x-[18px]',
      thumbOffPosition: 'translate-x-0.5',
      iconSize: 16,
      checkIconPosition: 'left-0.5',
      closeIconPosition: 'right-0.5',
    },
    md: {
      wrapper: 'w-12 h-6',
      thumb: 'w-5 h-5',
      thumbOnPosition: 'translate-x-[26px]',
      thumbOffPosition: 'translate-x-0.5',
      iconSize: 20,
      checkIconPosition: 'left-1',
      closeIconPosition: 'right-1',
    },
    lg: {
      wrapper: 'w-[60px] h-7',
      thumb: 'w-6 h-6',
      thumbOnPosition: 'translate-x-[34px]',
      thumbOffPosition: 'translate-x-0.5',
      iconSize: 24,
      checkIconPosition: 'left-1',
      closeIconPosition: 'right-1',
    },
  };

  const currentSize = sizeConfig[size];

  const renderCheckIcon = (props: SwitchIconProps) => (
    <CheckIcon height={props.height} width={props.width} className="text-neutral-50" />
  );

  const renderCloseIcon = (props: SwitchIconProps) => (
    <CloseIcon height={props.height} width={props.width} className="text-neutral-50" />
  );

  // Use provided icon or defaults
  const checkIcon = icon || renderCheckIcon;
  const closeIcon = icon || renderCloseIcon;

  const handleChange = (value: boolean) => {
    if (otherProps.onChange) {
      otherProps.onChange(value);
    }

    if (onValueChange) {
      const iconProps = {
        isSelected: value,
        className: '',
        width: `${currentSize.iconSize}px`,
        height: `${currentSize.iconSize}px`,
      };

      onValueChange(value, iconProps);
    }
  };

  return (
    <AriaSwitch ref={ref} className={baseStyles} onChange={handleChange} {...otherProps}>
      {(renderProps) => {
        const iconProps = {
          isSelected: renderProps.isSelected,
          className: '',
          width: `${currentSize.iconSize}px`,
          height: `${currentSize.iconSize}px`,
        };

        const renderedCheckIcon =
          typeof checkIcon === 'function'
            ? checkIcon(iconProps)
            : checkIcon && cloneElement(checkIcon as ReactElement, iconProps);

        const renderedCloseIcon =
          typeof closeIcon === 'function'
            ? closeIcon(iconProps)
            : closeIcon && cloneElement(closeIcon as ReactElement, iconProps);

        // Wrapper styles
        const wrapperStyles = clsx(
          'relative flex outline-none items-center justify-start rounded-full transition-all duration-300 ease-in-out',
          renderProps.isFocusVisible ? 'outline outline-2 outline-offset-2 outline-purple-600' : '',
          renderProps.isReadOnly ? 'pointer-events-none' : '',
          renderProps.isSelected
            ? 'bg-purple-600 hover:bg-purple-800'
            : 'bg-neutral-600 hover:bg-neutral-800',
          currentSize.wrapper,
        );

        // Thumb styles
        const thumbStyles = clsx(
          'absolute rounded-full bg-white shadow-md transform transition-transform duration-300 ease-in-out',
          renderProps.isSelected ? currentSize.thumbOnPosition : currentSize.thumbOffPosition,
          currentSize.thumb,
        );

        // Icon positioning styles
        const checkIconStyles = clsx(
          'absolute flex items-center justify-center z-0',
          currentSize.checkIconPosition,
        );

        const closeIconStyles = clsx(
          'absolute flex items-center justify-center z-0',
          currentSize.closeIconPosition,
        );

        return (
          <>
            <span>{label}</span>

            <span className={wrapperStyles}>
              {/* Check icon - on left side */}
              <span className={checkIconStyles}>{renderedCheckIcon}</span>

              {/* Close icon - on right side */}
              <span className={closeIconStyles}>{renderedCloseIcon}</span>

              {/* The moving thumb */}
              <span className={thumbStyles}></span>
            </span>

            {children && (
              <span aria-hidden="true" className="text-neutral-800">
                {typeof children === 'function' ? children(renderProps) : children}
              </span>
            )}
          </>
        );
      }}
    </AriaSwitch>
  );
}

const _Switch = forwardRef(Switch);
export { _Switch as Switch };
