import React from 'react';
import { BoxProps, BoxSize, BoxSpace, SilkeBox } from '../silke-box';
import ButtonContext from '../silke-button/context';
import { SilkeText } from '../silke-text/silke-text';
import styles from './silke-text-field.scss';
import { useTextFieldContext } from './text-field-context';
import { SilkeTextFieldItem } from './silke-text-field-item';
import { SilkeIconTooltip } from '../silke-tooltip';
import { SilkeInputSize } from './silke-text-field';

export type SilkeTextFieldOutlineProps = {
  error?: string;
  className?: string;
  label?: React.ReactNode;
  labelAlign?: BoxProps['hAlign'];
  // Makes text field flex
  flex?: boolean;
  size?: SilkeInputSize;
  kind?: 'default' | 'ghost' | 'zombie';
  width?: number | string;
  /** Flex gap added to the container with the children */
  gap?: BoxSpace;
  /** Horizontal padding added to the container with the children */
  hPad?: BoxSpace;
  hAlign?: BoxProps['hAlign'];
  vAlign?: BoxProps['vAlign'];
  /** Inline will add the label before the input field */
  inline?: boolean | 'label-inside' | 'label-left';

  /** Field required input (if string the string will be used as error msg) */
  /** Helpful tip or explanation of function of the field */
  help?: React.ReactNode;
  helpRight?: React.ReactNode;
  style?: React.CSSProperties;
  /** Can be used to insert components before and after text field by using <SilkeTextFieldItem> */
  children?: React.ReactNode;
  /** Id to link help label with (input should have aria-describedby) */
  helpId?: string;
  labelId?: string;
  labelUsingAria?: boolean;
  onClick?: (e: React.MouseEvent<HTMLElement>) => void;
  onMouseDown?: (e: React.MouseEvent<HTMLElement>) => void;
  onContextMenu?: (e: React.MouseEvent<HTMLElement>) => void;
  disabled?: boolean;
  tooltip?: string;
};

export const SilkeTextFieldOutline = React.forwardRef<HTMLDivElement, SilkeTextFieldOutlineProps>(
  (
    {
      size,
      kind,
      className,
      error,
      gap,
      hPad,
      hAlign,
      vAlign,
      inline,
      children,
      help,
      helpRight,
      helpId,
      label,
      labelId,
      labelUsingAria,
      width,
      flex,
      onClick,
      onMouseDown,
      onContextMenu,
      disabled,
      tooltip,
      labelAlign,
      style,
    }: SilkeTextFieldOutlineProps,
    ref,
  ) => {
    const context = useTextFieldContext();
    if (!size) ({ size = 'base' } = context);
    if (!kind) ({ kind } = context);
    if (!inline) ({ inline } = context);

    let cl = `${styles.root} ${styles[size === 's' ? 'small' : 'base']} ${styles[kind || 'default']}`;
    if (className) cl += ' ' + className;
    if (error) cl += ' ' + styles.error;
    if (inline) cl += ' ' + styles.inline;
    if (disabled) {
      cl += ' ' + styles.disabled;
    }

    const showError = Boolean(error);
    const showHelp = Boolean((help || helpRight) && !error);
    const boxSize: BoxSize = size === 's' ? 's' : 'base';

    const labelComponent = label && (
      <SilkeBox
        vAlign="center"
        hAlign={labelAlign}
        flex={inline !== 'label-left'}
        width={inline === 'label-left' ? 'xxl' : undefined}
      >
        <SilkeText
          className={styles.label}
          tag="label"
          id={labelUsingAria ? labelId : undefined}
          htmlFor={!labelUsingAria ? labelId : undefined}
          color="neutral-100"
          size={size === 's' ? 'small' : 'base'}
        >
          {label}
        </SilkeText>
        {tooltip && (
          <SilkeBox style={{ height: '10px', marginTop: '-13px' }}>
            <SilkeIconTooltip tooltip={tooltip} icon="tooltip" />
          </SilkeBox>
        )}
      </SilkeBox>
    );

    if (width) {
      style = { ...style, minWidth: width, maxWidth: width, width };
    } else if (flex) {
      style = { ...style, flex: 1 };
    }

    return (
      <SilkeBox column className={styles.wrapper} style={style} onContextMenu={onContextMenu}>
        <SilkeBox
          data-size={`data-input-${size}`}
          tag="div"
          column={!inline}
          gap={'xs'}
          vAlign="center"
          className={cl}
          onClick={onClick}
          onMouseDown={onMouseDown}
        >
          {inline !== 'label-inside' && labelComponent}

          <ButtonContext kind="ghost" size="base">
            <SilkeBox
              gap={gap}
              hPad={hPad}
              hAlign={hAlign}
              vAlign={vAlign}
              className={styles.field}
              flex={!!inline}
              ref={ref}
            >
              {labelComponent && inline === 'label-inside' && (
                <SilkeTextFieldItem before minWidth={boxSize} hPad="xs">
                  {labelComponent}
                </SilkeTextFieldItem>
              )}
              {children}
            </SilkeBox>
          </ButtonContext>

          {!inline && (showHelp || showError) && (
            <SilkeBox hAlign="spread" className={styles.help}>
              {showHelp && help && (
                <SilkeText flex id={helpId} size={size === 's' ? 'micro' : 'base'}>
                  {help}
                </SilkeText>
              )}
              {showHelp && helpRight && <SilkeText>{helpRight}</SilkeText>}
              {showError && (
                <SilkeText
                  flex
                  aria-live="polite"
                  role="alert"
                  size={size === 's' ? 'micro' : 'base'}
                >
                  {error}
                </SilkeText>
              )}
            </SilkeBox>
          )}
        </SilkeBox>
      </SilkeBox>
    );
  },
);

SilkeTextFieldOutline.displayName = 'SilkeTextFieldOutline';
