import React, { useEffect, useState, useRef, useCallback } from 'react';
import { Input, Balloon, Icon } from '@alife/cn-ui';
import classnames from 'classnames';
import {
  volumeInputProps,
  valueProps,
  currentEnum,
} from 'src/types/op-volume-input';
import OPLayout from '../op-layout';
import event from '../event';

import './index.scss';

const { Tooltip } = Balloon;
const { Content } = OPLayout;

export default function OPVolumeInput(props: volumeInputProps) {
  const {
    value: propValue = {
      length: '',
      width: '',
      height: '',
    },
    autoFocus = true,
    state = '',
    unit = 'cm',
    current: propCurrent = 'length',
    locale = {
      length: '长',
      width: '宽',
      height: '高',
      tooltip: '按回车确认',
    },
    onChange,
    onEnter,
    size = 'large',
  } = props;

  const [focus, setFocus] = useState({
    length: false,
    width: false,
    height: false,
  });
  const [value, setValue] = useState<valueProps | null>(propValue);
  const [current, setCurrent] = useState<currentEnum>(propCurrent);

  const lengthRef = useRef<HTMLInputElement & Input>(null);
  const widthRef = useRef<HTMLInputElement & Input>(null);
  const heightRef = useRef<HTMLInputElement & Input>(null);

  const isFocus = focus.length || focus.width || focus.height;

  const handleChangeInput = useCallback(
    (type: string) => {
      let newCurrent = '' as currentEnum;
      switch (current) {
        case 'length':
          if (type === 'left') {
            newCurrent = 'height';
          } else {
            newCurrent = 'width';
          }
          break;
        case 'width':
          if (type === 'left') {
            newCurrent = 'length';
          } else {
            newCurrent = 'height';
          }
          break;
        case 'height':
          if (type === 'left') {
            newCurrent = 'width';
          } else {
            newCurrent = 'length';
          }
          break;
        default:
          break;
      }
      setCurrent(newCurrent);
    },
    [current],
  );

  const handleLeft = useCallback(() => {
    handleChangeInput('left');
  }, [handleChangeInput]);

  const handleRight = useCallback(() => {
    handleChangeInput('right');
  }, [handleChangeInput]);

  const handleEnter = useCallback(() => {
    let newCurrent = '' as currentEnum;
    const currentValue = value?.[current] as currentEnum;
    if (!currentValue) {
      return;
    }
    switch (current) {
      case 'length':
        newCurrent = 'width';
        break;
      case 'width':
        newCurrent = 'height';
        break;
      case 'height':
        newCurrent = 'height';
        onEnter?.(value);
        break;
      default:
        break;
    }
    setCurrent(newCurrent);
  }, [current, onEnter, value]);

  const onInputFocus = (type: currentEnum) => {
    setFocus({
      length: false,
      width: false,
      height: false,
      [type]: true,
    });
  };

  const onInputBlur = (type: currentEnum) => {
    setFocus({
      ...focus,
      [type]: false,
    });
  };

  const handleChange = (type: currentEnum, v: string) => {
    if (/^\d+\.*\d*$/.test(v) || !v) {
      const newValue = {
        ...value,
        [type]: v.trim(),
      } as valueProps;
      setValue(newValue);
      onChange &&
        onChange({
          current,
          value: {
            ...value,
            [type]: v.trim(),
          },
        });
    }
  };

  const renderText = (text: string, unit: string) => (
    <>
      <span className='op-volume-input-text'>{text}</span>
      <span className='op-volume-input-unit'>({unit})</span>
    </>
  );

  useEffect(() => {
    const { length, width, height } = value as valueProps;
    if (autoFocus) {
      switch (current) {
        case 'length': {
          const cur = lengthRef.current;
          if (cur) {
            cur.focus();
            cur.getInputNode().setSelectionRange(length.length, length.length);
          }
          break;
        }
        case 'width': {
          const cur = widthRef.current;
          if (cur) {
            cur.focus();
            cur.getInputNode().setSelectionRange(width.length, width.length);
          }
          break;
        }
        case 'height': {
          const cur = heightRef.current;
          if (cur) {
            cur.focus();
            cur.getInputNode().setSelectionRange(height.length, height.length);
          }
          break;
        }
        default:
          break;
      }
    }
    event.bind('enter', handleEnter);
    event.bind('left', handleLeft);
    event.bind('right', handleRight);
    return () => {
      event.unbind('enter', handleEnter);
      event.unbind('left', handleLeft);
      event.unbind('right', handleRight);
    };
  }, [autoFocus, current, value, handleEnter, handleLeft, handleRight]);

  return (
    <div
      className={classnames(
        'op-volume-input',
        isFocus && 'op-volume-input-focus',
        state && `op-volume-input-${state}`,
        size && `op-volume-input-${size}`,
      )}
    >
      <OPLayout hoz>
        <Content auto>
          <Input
            innerBefore={renderText(locale.length, unit)}
            ref={lengthRef}
            value={value?.length}
            size='large'
            className={classnames(
              'op-volume-input-length',
              focus.length && 'op-volume-input-focus',
            )}
            onFocus={() => onInputFocus('length')}
            onBlur={() => onInputBlur('length')}
            trim
            onChange={(val) => handleChange('length', val)}
          />
          <Tooltip
            triggerType='focus'
            align='br'
            popupClassName='op-balloon'
            popupProps={{
              target: lengthRef.current,
              visible: focus.length,
            }}
          >
            {locale.tooltip}
          </Tooltip>
        </Content>
        <Content size={30} middle center>
          <Icon type='close' size='large' className='op-volume-input-icon' />
        </Content>
        <Content auto>
          <Input
            innerBefore={renderText(locale.width, unit)}
            ref={widthRef}
            onFocus={() => onInputFocus('width')}
            onBlur={() => onInputBlur('width')}
            value={value?.width}
            size='large'
            className={`op-volume-input-width ${
              focus.width ? 'op-volume-input-focus' : ''
            }`}
            trim
            onChange={(val) => handleChange('width', val)}
          />
          <Tooltip
            triggerType='focus'
            align='br'
            popupClassName='op-balloon'
            popupProps={{
              target: widthRef.current,
              visible: focus.width,
            }}
          >
            {locale.tooltip}
          </Tooltip>
        </Content>
        <Content size={30} middle center>
          <Icon type='close' size='large' className='op-volume-input-icon' />
        </Content>
        <Content auto>
          <Input
            innerBefore={renderText(locale.height, unit)}
            ref={heightRef}
            onFocus={() => onInputFocus('height')}
            onBlur={() => onInputBlur('height')}
            value={value?.height}
            size='large'
            className={`op-volume-input-height ${
              focus.height ? 'op-volume-input-focus' : ''
            }`}
            trim
            onChange={(val) => handleChange('height', val)}
          />
          <Tooltip
            triggerType='focus'
            align='br'
            popupClassName='op-balloon'
            popupProps={{
              target: heightRef.current,
              visible: focus.height,
            }}
          >
            {locale.tooltip}
          </Tooltip>
        </Content>
      </OPLayout>
    </div>
  );
}
