/** @jsxRuntime classic */
/** @jsx jsx */
import React, {
  FC,
  useState,
  useRef,
  useEffect,
  ChangeEvent,
  MutableRefObject,
} from 'react';

import cx from 'classnames';
import { jsx, Theme, useTheme } from '@emotion/react';
import {
  StyledInput,
  DeleteButtonStyle,
  InputContainer,
  RightButton,
  ArrowsButton,
} from './style';
import { getIcon, BnRemove, BnArrowUp, BnArrowDown } from '../../icons';
import { BnIcon } from '../icons_v2';
import { capitalize } from '../../functions';
import { Tooltip } from '../Tooltip';
import { ErrorMessage } from '../ErrorMessage';
import { InputProps } from '../../types';
import Cleave from 'cleave.js/react';

const useClickOutside = (
  ref: React.MutableRefObject<HTMLDivElement>,
  callback: (val: number) => void,
  innerValue: string
) => {
  const handleClick = (e: Event) => {
    if (ref) {
      if (ref.current && !ref.current.contains(e.target as Node)) {
        callback(Number(innerValue));
      }
    }
  };
  React.useEffect(() => {
    document.addEventListener('click', handleClick);
    return () => {
      document.removeEventListener('click', handleClick);
    };
  });
};

export const Input: FC<
  InputProps & React.InputHTMLAttributes<HTMLInputElement>
> = ({
  leftIcon = '',
  rightIcon = '',
  children,
  sizer = 'S',
  label = '',
  info = '',
  helper = '',
  helperContent = '',
  rightButton = '',
  format = 'default',
  onRightButtonClick = () => {},
  isVisited = false,
  withArrows = false,
  error = undefined,
  hideError = false,
  noLabel = false,
  disableTrailing = false,

  setChange = () => {},
  clear = () => {},
  clickOutside = (val) => {},
  // colors = ThemeColors,
  ...rest
}) => {
  const [isFocus, setFocus] = useState<boolean>(false);
  // const [innerValue, setInnerValue] = useState<string>('');
  const [isHover, setHover] = useState<boolean>(false);
  const [visited, setVisited] = useState<boolean>(false);

  const inputRef = useRef(null);
  const inputContainerRef = useRef<HTMLDivElement>(null);
  const colors = useTheme();
  // const { colors: ThemeC } = useColors();
  const newClassName = rest.className;
  delete rest.className;

  useClickOutside(
    inputContainerRef as MutableRefObject<HTMLDivElement>,
    clickOutside,
    String(rest.value)
  );

  useEffect(() => {
    setVisited(isVisited);
  }, [isVisited]);

  const disabled = rest.disabled;

  return (
    <InputContainer
      className={cx(
        {
          M: sizer === 'M',
          S: sizer === 'S',
          disabled,
        },
        newClassName
      )}
      theme={{ ...colors }}
      ref={inputContainerRef}
      style={{ ...rest.style }}
      {...rest}
    >
      {(label || noLabel) && (
        <div className="label">
          <div>
            {capitalize(label)}
            {rest.required && !noLabel && ' *'}
          </div>
          {info && <Tooltip content={info}>{getIcon('info', 'l')}</Tooltip>}
        </div>
      )}
      <StyledInput
        theme={{ ...colors }}
        className={cx({
          focus: isFocus,
          error: error && visited,
          hover: isHover,
          M: sizer === 'M',
          S: sizer === 'S',
          disabled,
        })}
        onClick={() => {
          if (inputRef.current) {
            //@ts-ignore
            inputRef.current.focus();
          }
        }}
        onMouseEnter={() => {
          setHover(true);
        }}
        onMouseLeave={() => {
          setHover(false);
        }}
      >
        <div style={{ position: 'relative', width: '100%', display: 'flex' }}>
          {leftIcon && (
            <BnIcon
              icon={leftIcon}
              style={{ paddingRight: '4px', height: '20px', width: '20px' }}
            />
          )}
          {format === 'time' ? (
            <Cleave
              options={{
                time: true,
                timePattern: ['h', 'm'],
                timeFormat: '12',
              }}
              {...rest}
              disabled={disabled}
              onFocus={(e) => {
                setFocus(true);

                if (rest.onFocus) {
                  rest.onFocus(e);
                }
              }}
              onChange={(e) => {
                // setInnerValue(e.target.value);
                if (rest.onChange) {
                  rest.onChange(e);
                }
              }}
              onBlur={(e) => {
                setFocus(false);
                setVisited(true);
                if (rest.onBlur) {
                  rest.onBlur(e);
                }
              }}
            />
          ) : (
            <input
              ref={inputRef}
              disabled={disabled}
              {...rest}
              value={rest.value}
              onChange={(e) => {
                // setInnerValue(e.target.value);
                if (rest.onChange) {
                  rest.onChange(e);
                }
              }}
              onFocus={(e) => {
                setFocus(true);

                if (rest.onFocus) {
                  rest.onFocus(e);
                }
              }}
              onBlur={(e) => {
                setFocus(false);
                setVisited(true);
                if (rest.onBlur) {
                  rest.onBlur(e);
                }
              }}
            />
          )}
          {!disableTrailing && isHover && !disabled && (
            <DeleteButton
              onClick={() => {
                if (inputRef && inputRef.current) {
                  // @ts-ignore: Object is possibly 'null'.
                  inputRef.current.focus();
                }
                // setInnerValue('');
                if (clear) {
                  clear();
                }
              }}
              theme={{ ...colors }}
            />
          )}
          {rightIcon && (
            <BnIcon icon={rightIcon} style={{ paddingLeft: '4px' }} />
          )}
        </div>
        {withArrows && rest.type === 'number' && (
          <ArrowsButton theme={{ ...colors }}>
            <div
              onClick={() => {
                let v = rest.value as number;

                let e = {
                  target: {
                    value: v ? Number(v) + 1 : 1,
                  },
                };

                // setInnerValue(String(v + 1));
                if (rest.onChange) {
                  rest.onChange(
                    (e as unknown) as ChangeEvent<HTMLInputElement>
                  );
                }
              }}
            >
              <BnArrowUp />
            </div>
            <div
              onClick={() => {
                let v = rest.value as number;
                let e = {
                  target: {
                    value: v ? Number(v) - 1 : 1,
                  },
                };
                // setInnerValue(String(v - 1));
                if (rest.onChange) {
                  rest.onChange(
                    (e as unknown) as ChangeEvent<HTMLInputElement>
                  );
                }
              }}
            >
              <BnArrowDown />
            </div>
          </ArrowsButton>
        )}
        {rightButton && (
          <RightButton theme={{ ...colors }}>
            <button onClick={onRightButtonClick}>{rightButton}</button>
          </RightButton>
        )}
      </StyledInput>

      {helper && (
        <div className="helper">
          {helperContent && (
            <Tooltip content={helperContent}>{getIcon('info', 'r')}</Tooltip>
          )}
          <div>{capitalize(helper)}</div>
        </div>
      )}
      {!hideError && (
        <div className="error" style={{ minHeight: '15px' }}>
          {visited && <ErrorMessage error={error || ''} />}
        </div>
      )}
    </InputContainer>
  );
};

interface DeleteButtonProps {
  theme: Theme;
  onClick: () => void;
}
const DeleteButton = ({ theme, onClick }: DeleteButtonProps) => {
  return (
    <DeleteButtonStyle tabIndex={-1} theme={theme} onClick={onClick}>
      <BnRemove />
    </DeleteButtonStyle>
  );
};
