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

import { Input } from '../input';
import { Label } from '../label';
import { Triangle } from '../iconography/triangle';

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',
    },
  },
  defaultVariants: {},
});

type InputWithLabelStylesProps = VariantProps<typeof inputWithLabelStyles>;

export type InputWithLabelProps = InputWithLabelStylesProps & {
  label: string;
  append?: ReactNode;
  errorMessage?: string;
  labelProps?: ComponentPropsWithoutRef<'label'>;
} & ComponentPropsWithRef<'input'>;

export type InputWithLabelRef = HTMLInputElement;

export const InputWithLabel = forwardRef<InputWithLabelRef, InputWithLabelProps>(
  ({ className, label, append, errorMessage, status, 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} />
            {!append && !errorMessage ? null : (
              <div className="c-input-with-label-append" title={errorMessage}>
                {errorMessage ? <Triangle /> : append}
              </div>
            )}
          </span>
        </Label>
      </>
    );
  },
);

InputWithLabel.displayName = 'InputWithLabel';
