import { ComponentPropsWithoutRef, ComponentPropsWithRef, forwardRef, ReactNode } from 'react';
import { cva, cx, VariantProps } from 'class-variance-authority';

import { Icon } from '../iconography';
import { Input } from '../input';
import { Label } from '../label';
import { Tooltip } from '../tooltip';

const inputWithLabelStyles = cva(['c-input-with-label'], {
  variants: {
    variant: {
      default: '',
      elevated: 'c-input-with-label-elevated',
      outlined: 'c-input-with-label-outlined',
    },
    status: {
      error: 'c-input-with-label--error',
      warning: 'c-input-with-label--warning',
    },
  },
  defaultVariants: {},
});

type InputWithLabelStylesProps = VariantProps<typeof inputWithLabelStyles>;

export type InputWithLabelProps = InputWithLabelStylesProps & {
  label?: string;
  append?: ReactNode;
  /**
   * @deprecated Use statusMessage instead
   */
  errorMessage?: string;
  statusMessage?: string;
  labelProps?: ComponentPropsWithoutRef<'label'>;
} & ComponentPropsWithRef<'input'>;

export type InputWithLabelRef = HTMLInputElement;

export const InputWithLabel = forwardRef<InputWithLabelRef, InputWithLabelProps>(
  ({ className, label, append, errorMessage, status, statusMessage, variant, id, labelProps, ...delegated }, ref) => {
    const { className: labelClassName, ...labelPropsRest } = labelProps ?? {};

    return (
      <>
        <Label
          className={inputWithLabelStyles({ status, variant, className: labelClassName })}
          htmlFor={id}
          {...labelPropsRest}
        >
          {label}
          <span className="c-input-with-label-input-wrap">
            <Input className={cx('c-input-with-label-input', className)} ref={ref} id={id} {...delegated} />
            {!!(errorMessage ?? statusMessage) ? (
              <Tooltip content={errorMessage ?? statusMessage} variant={status}>
                <div data-testid="input-with-label-status-message" className="c-input-with-label-append">
                  {status === 'error' ? <Icon.Error width={20} height={20} /> : <Icon.Warning width={20} height={20} />}
                </div>
              </Tooltip>
            ) : (
              !!append && <div className="c-input-with-label-append">{append}</div>
            )}
          </span>
        </Label>
      </>
    );
  },
);

InputWithLabel.displayName = 'InputWithLabel';
