import React, { useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
import { ErrorMessage, InputElement, InputWrap, Tips, Info, TextAreaElement, SIcon } from './style';
import useReducer from 'utils/useReducerHelper';
import { useSpring } from 'react-spring';
import { IInput } from './types';

const Input = function(props: IInput, ref: React.RefObject<any>) {
    const {
        value,
        onChange,
        validator,
        preValidator,
        tips,
        clear,
        size,
        textarea,
        style,
        className,
        onEnter,
        icon,
        iconPosition,
        iconClick,
        iconColor = '#b6bbc7',
        ...rest
    } = props;
    const [state, dispatch] = useReducer({
        value,
        errorMessage: '',
        validateResult: true, // if true no error, if is string: has error and its a errorMsg
    });

    const renderValue = 'value' in props ? value : state.value || '';
    const firstRun = useRef(true);
    useEffect(() => {
        // skip first run validate check
        if (validator && !firstRun.current) {
            const validateResult = validator(renderValue);
            const state: any = { validateResult };
            if (validateResult !== true) {
                // copy errMsg from validateResult for animation purpose
                state.errorMessage = validateResult;
            }
            dispatch(state);
        }
        firstRun.current = false;
    }, [validator, renderValue]);
    const inputRef: any = useRef();
    const valid = state.validateResult === true;
    useImperativeHandle(ref, () => ({ isValid: valid, input: inputRef.current }));
    const errorStyle = useSpring({
        height: valid ? 0 : 20,
        opacity: valid ? 0 : 1,
        transform: `translate3d(0, -${valid ? 150 : 0}%, 0)`,
    });
    const RenderedElement = textarea ? TextAreaElement : InputElement;
    const showClose = !textarea && clear && renderValue && state.validateResult === true;
    return (
        <InputWrap width={rest.width} style={style} className={className}>
            <RenderedElement
                {...rest}
                value={renderValue}
                hasError={typeof state.validateResult === 'string'}
                hasClear={clear && renderValue}
                onChange={changeHandler}
                onBlur={blurHandler}
                onKeyDown={(e: any) => {
                    if (e.keyCode === 13) {
                        onEnter && onEnter(e.target.value);
                    }
                    const onKeyDown = (rest as any).onKeyDown;
                    onKeyDown && onKeyDown(e);
                }}
                style={{ paddingLeft: icon && iconPosition === 'start' ? 30 : undefined }}
                ref={inputRef}
            />
            {tips && state.validateResult === true && <Tips>{tips}</Tips>}

            <React.Fragment>
                <ErrorMessage size={size} style={errorStyle}>
                    {state.errorMessage}
                </ErrorMessage>
                {!textarea && !valid && <Info />}
            </React.Fragment>
            {!showClose && icon && (
                <SIcon name={icon} iconPosition={iconPosition} color={iconColor} onClick={iconClick} />
            )}
            {showClose && (
                <SIcon
                    name="CloseInvert"
                    onClick={(e: React.ChangeEvent<HTMLInputElement>) => {
                        (inputRef.current as HTMLInputElement).focus();
                        dispatch({ value: '' });
                        if (onChange) {
                            e.target = inputRef.current as HTMLInputElement;
                            e.target.value = '';
                            onChange(e);
                        }
                    }}
                />
            )}
        </InputWrap>
    );

    function changeHandler(e: React.ChangeEvent<HTMLInputElement>) {
        const preCheck = preValidator ? preValidator(e.target.value) : true;
        typeof preCheck === 'string' && dispatch({ errorMessage: preCheck });
        preValidator && dispatch({ validateResult: preCheck });
        if (preCheck !== true) {
            return;
        }
        if (!('value' in props)) {
            dispatch({ value: e.target.value });
        }
        if (onChange) {
            onChange(e);
        }
    }

    function blurHandler(e: React.ChangeEvent<HTMLInputElement>) {
        const preCheck = preValidator ? preValidator(e.target.value) : true;
        typeof preCheck === 'string' && dispatch({ errorMessage: preCheck });
        preValidator && dispatch({ validateResult: preCheck });

        const onBlur = (rest as any).onBlur;

        if (onBlur) {
            onBlur(e);
        }
    }
};

//@ts-ignore
const forwardRefExoticComponent = forwardRef(Input);
forwardRefExoticComponent.defaultProps = {
    size: 'large',
    width: '120px',
};
export default forwardRefExoticComponent;

export const IntegerValues = (value: string) => /^-?\d*$/.test(value) || '只能输入整数';
export const PositiveIntegerValues = (value: string) => /^\d*$/.test(value) || '只能输入正整数';
export const PositiveIntegerWithLimit = (limit: number, msg = `只能输入正整数，且不能大于${limit}`) => (
    value: string
) => (/^\d*$/.test(value) && (value === '' || parseInt(value) <= limit)) || msg;
export const FloatPointValues = (value: string) => /^-?\d*[.,]?\d*$/.test(value) || '只能输入数字';
export const TwoDecimalAtMost = (value: string) =>
    /^-?\d*[.,]?\d{0,2}$/.test(value) || '只能输入数字，小数位数不能大于2';
