import clsx from 'clsx';
import {BaseFieldProps} from './base-field-props';
import {ButtonSize, getButtonSizeStyle} from '../../buttons/button-size';

export interface InputFieldStyle {
  label: string;
  input: string;
  wrapper: string;
  inputWrapper: string;
  adornment: string;
  append: {size: string; radius: string};
  size: {font: string; height: string};
  description: string;
  error: string;
}

type InputFieldStyleProps = Omit<
  BaseFieldProps,
  'value' | 'defaultValue' | 'onChange'
>;

export function getInputFieldClassNames(
  props: InputFieldStyleProps = {},
): InputFieldStyle {
  const {
    size = 'md',
    startAppend,
    endAppend,
    className,
    labelPosition,
    labelDisplay = 'block',
    inputClassName,
    inputWrapperClassName,
    unstyled,
    invalid,
    disabled,
    background = 'bg-transparent',
    flexibleHeight,
    inputShadow = 'shadow-sm',
    descriptionPosition = 'bottom',
    inputRing,
    inputFontSize,
    labelSuffix,
  } = {...props};

  if (unstyled) {
    return {
      label: '',
      input: inputClassName || '',
      wrapper: className || '',
      inputWrapper: inputWrapperClassName || '',
      adornment: '',
      append: {size: '', radius: ''},
      size: {font: '', height: ''},
      description: '',
      error: '',
    };
  }

  const sizeClass = inputSizeClass({
    size: props.size,
    flexibleHeight,
  });
  if (inputFontSize) {
    sizeClass.font = inputFontSize;
  }

  const isInputGroup = startAppend || endAppend;

  const ringColor = invalid
    ? 'focus:ring-danger/focus focus:border-danger/60'
    : 'focus:ring-primary/focus focus:border-primary/60';
  const ringClassName = inputRing || `focus:ring ${ringColor}`;

  const radius = getRadius(props);

  return {
    label: clsx(
      labelDisplay,
      'first-letter:capitalize text-left whitespace-nowrap',
      disabled && 'text-disabled',
      sizeClass.font,
      labelSuffix ? '' : labelPosition === 'side' ? 'mr-16' : 'mb-4',
    ),
    input: clsx(
      'block text-left relative w-full appearance-none transition-shadow text',
      background,

      // radius
      radius.input,

      getInputBorder(props),
      !disabled && `${ringClassName} focus:outline-none ${inputShadow}`,
      disabled && 'text-disabled cursor-not-allowed',
      inputClassName,
      sizeClass.font,
      sizeClass.height,
      getInputPadding(props),
    ),
    adornment: iconSizeClass(size),
    append: {
      size: getButtonSizeStyle(size),
      radius: radius.append,
    },
    wrapper: clsx(className, sizeClass.font, {
      'flex items-center': labelPosition === 'side',
    }),
    inputWrapper: clsx(
      'isolate relative',
      inputWrapperClassName,
      isInputGroup && 'flex items-stretch',
    ),
    size: sizeClass,
    description: `text-muted ${
      descriptionPosition === 'bottom' ? 'pt-10' : 'pb-10'
    } text-xs`,
    error: 'text-danger pt-10 text-xs',
  };
}

function getInputBorder({
  startAppend,
  endAppend,
  inputBorder,
  invalid,
}: InputFieldStyleProps) {
  if (inputBorder) return inputBorder;

  const isInputGroup = startAppend || endAppend;
  const borderColor = invalid ? 'border-danger' : 'border-divider';

  if (!isInputGroup) {
    return `${borderColor} border`;
  }
  if (startAppend) {
    return `${borderColor} border-y border-r`;
  }
  return `${borderColor} border-y border-l`;
}

function getInputPadding({
  startAdornment,
  endAdornment,
  inputRadius,
}: InputFieldStyleProps) {
  if (inputRadius === 'rounded-full') {
    return clsx(
      startAdornment ? 'pl-54' : 'pl-28',
      endAdornment ? 'pr-54' : 'pr-28',
    );
  }
  return clsx(
    startAdornment ? 'pl-46' : 'pl-12',
    endAdornment ? 'pr-46' : 'pr-12',
  );
}

function getRadius(props: InputFieldStyleProps): {
  input: string;
  append: string;
} {
  const {startAppend, endAppend, inputRadius} = props;
  const isInputGroup = startAppend || endAppend;

  if (inputRadius === 'rounded-full') {
    return {
      input: clsx(
        !isInputGroup && 'rounded-full',
        startAppend && 'rounded-r-full rounded-l-none',
        endAppend && 'rounded-l-full rounded-r-none',
      ),
      append: startAppend ? 'rounded-l-full' : 'rounded-r-full',
    };
  } else if (inputRadius === 'rounded-none') {
    return {
      input: '',
      append: '',
    };
  } else if (inputRadius) {
    return {
      input: inputRadius,
      append: inputRadius,
    };
  }
  return {
    input: clsx(
      !isInputGroup && 'rounded-input',
      startAppend && 'rounded-input-r rounded-l-none',
      endAppend && 'rounded-input-l rounded-r-none',
    ),
    append: startAppend ? 'rounded-input-l' : 'rounded-input-r',
  };
}

function inputSizeClass({size, flexibleHeight}: BaseFieldProps) {
  switch (size) {
    case '2xs':
      return {font: 'text-xs', height: flexibleHeight ? 'min-h-24' : 'h-24'};
    case 'xs':
      return {font: 'text-xs', height: flexibleHeight ? 'min-h-30' : 'h-30'};
    case 'sm':
      return {font: 'text-sm', height: flexibleHeight ? 'min-h-36' : 'h-36'};
    case 'lg':
      return {
        font: 'text-md md:text-lg',
        height: flexibleHeight ? 'min-h-50' : 'h-50',
      };
    case 'xl':
      return {font: 'text-xl', height: flexibleHeight ? 'min-h-60' : 'h-60'};
    default:
      return {font: 'text-sm', height: flexibleHeight ? 'min-h-42' : 'h-42'};
  }
}

function iconSizeClass(size?: ButtonSize): string {
  switch (size) {
    case '2xs':
      return 'icon-2xs';
    case 'xs':
      return 'icon-xs';
    case 'sm':
      return 'icon-sm';
    case 'md':
      return 'icon-sm';
    case 'lg':
      return 'icon-lg';
    case 'xl':
      return 'icon-xl';
    default:
      // can't return "size" variable here, append in field will not work with it
      return '';
  }
}
